0

Inside a table view cell, I have a textview that is both reduced in size and disappearing with alpha.

//self is tableviewcell
self.hiddenCon.isActive = true  //this is a contraint of the textview, making it smaller
self.setNeedsUpdateConstraints()
self.layoutIfNeeded()
UIView.animate(withDuration: 0.25) {
        self.textview.alpha = 0 //I also want to make it disappear while going smaller
        self.layoutIfNeeded()
}

But it ends up, going smaller, but no alpha change

erotsppa
  • 14,248
  • 33
  • 123
  • 181
  • 1
    Why do you call `self.layoutIfNeeded()` twice? – iOSDev Feb 06 '20 at 05:23
  • Its recommended see https://stackoverflow.com/questions/12622424/how-do-i-animate-constraint-changes – erotsppa Feb 06 '20 at 05:24
  • Try this: UIView.animate(withDuration: 0.25) { self.hiddenCon.isActive = true self.textview.alpha = 0 //I also want to make it disappear while going smaller self.layoutIfNeeded() } – OnkarK Feb 06 '20 at 07:04
  • It is looks like issue consider only UITextView. As soon as you want to change alpha of UITextView together with its frame, then it is not behave correctly. Doesn't matter if do you wrapper UITextView to some UIView and change its alpha instead. Only one quick fix is do not change frame of UITextView, but only frame of superview wraper. It will not be perfect, but maybe good enough. – Lukáš Mareda Feb 06 '20 at 09:50
  • @erotsppa - are you trying to decrease the cell height also? Or just decrease the height of the text view? – DonMag Feb 06 '20 at 13:04
  • Cell height also. I have tableview.beginupdates/endupdates after this code – erotsppa Feb 06 '20 at 13:09
  • @erotsppa - are you using Storyboard cell prototype to design the cell? Or doing it from code? – DonMag Feb 06 '20 at 13:17
  • Using toryboard – erotsppa Feb 06 '20 at 13:20
  • “Why do you call self.layoutIfNeeded() twice?” ... “Its recommended” ... Look carefully at that example: Sure, they call it before they animate, but notice that they then change the constraints _after_ the first call and then animate the constraint change with the second call inside the animation block. But you’re not changing constraints in between these two calls. So you’re not animating any constraints in the code you’ve shared with us. – Rob Feb 06 '20 at 21:24
  • Bottom line, you generally don’t have that first `layoutIfNeeded`, but just call it inside the animation block. The only time you’d have another call before you change the constraints is if you might have other constraint changes in flight which you don’t want to animate (which is a very unusual edge case). Also the `needsUpdateConstraints` is entirely redundant and should be eliminated. – Rob Feb 06 '20 at 23:00
  • @Rob its besides the point the code doesn't work if you call it once, 2 or 3 times – erotsppa Feb 06 '20 at 23:52
  • @LukášMareda I moved the TextView under a UIView and changed the constraint (height) of the UIView only and same problem – erotsppa Feb 06 '20 at 23:56
  • Agreed. I only pointed it out because you said under the impression it was recommended, which it is not. But I apologize if you took offense. The bigger issue is that, setting these comments aside, the above code is not enough to manifest the problem you describe. We want to help you, but we need a [MCVE](https://stackoverflow.com/help/mcve). I might suggest creating a blank project (not your existing codebase) that manifests this problem and we’re happy to take a look. But we cannot reproduce your problem on the basis of what’s been shared thus far. – Rob Feb 07 '20 at 00:02
  • 1
    @Rob fair enough, the sample project cannot be found here https://github.com/dpyy/tabletest.git – erotsppa Feb 07 '20 at 00:03
  • @erotsppa As I said, it is looks like it is problem only with UITextView. If you want, I can create the answer with an example what I suggested to you yesterday. – Lukáš Mareda Feb 07 '20 at 08:07
  • @LukášMareda yes please that would helpful if you can provide a working solution – erotsppa Feb 07 '20 at 13:01
  • @erotsppa - see the notes on my answer. The issue is that you have **scrolling** disabled on your text view. Enable it, and the text fades as desired. – DonMag Feb 07 '20 at 19:54

1 Answers1

0

You may be able to fix things the way you have them, but...

Instead of activating a second constraint (you're not showing where you're deactivating a showingCon constraint), I'm going to suggest you use a single Height constraint for your text view, and change the .constant value...

Here's a very basic example that is working for me:

import UIKit

class ShrinkTextViewCell: UITableViewCell {

    @IBOutlet var textViewHeightConstraint: NSLayoutConstraint!
    @IBOutlet var theTextView: UITextView!

    var tableUpdateCallback: (()->())?

    @IBAction func didTap(_ sender: Any) {

        if theTextView.alpha > 0.0 {

            UIView.animate(withDuration: 0.5) {
                self.theTextView.alpha = 0.0
                self.textViewHeightConstraint.constant = 0
                self.contentView.layoutIfNeeded()
                self.tableUpdateCallback?()
            }

        } else {

            UIView.animate(withDuration: 0.5) {
                self.theTextView.alpha = 1.0
                self.textViewHeightConstraint.constant = 128
                self.contentView.layoutIfNeeded()
                self.tableUpdateCallback?()
            }

        }
    }

}

class ShrinkTextViewTableViewController: UITableViewController {

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let c = tableView.dequeueReusableCell(withIdentifier: "ShrinkTextViewCell", for: indexPath) as! ShrinkTextViewCell
        c.tableUpdateCallback = {
            tableView.beginUpdates()
            tableView.endUpdates()
        }
        return c

    }
}

and here is the source of the Storyboard:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="9iy-6q-gap">
    <device id="retina4_7" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Shrink Text View Table View Controller-->
        <scene sceneID="oHl-Pu-bIJ">
            <objects>
                <tableViewController id="wSO-s3-dB0" customClass="ShrinkTextViewTableViewController" customModule="scratchy" customModuleProvider="target" sceneMemberID="viewController">
                    <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="WtR-bt-uSy">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                        <prototypes>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="ShrinkTextViewCell" rowHeight="189" id="gZx-b8-Hf3" customClass="ShrinkTextViewCell" customModule="scratchy" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="28" width="375" height="189"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="gZx-b8-Hf3" id="xmG-jI-EeI">
                                    <rect key="frame" x="0.0" y="0.0" width="375" height="189"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="CGL-ug-wBr">
                                            <rect key="frame" x="16" y="11" width="240" height="128"/>
                                            <color key="backgroundColor" red="0.99953407049999998" green="0.98835557699999999" blue="0.47265523669999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <constraints>
                                                <constraint firstAttribute="width" constant="240" id="Dip-pf-MUH"/>
                                                <constraint firstAttribute="height" priority="999" constant="128" id="mK2-jh-d1y"/>
                                            </constraints>
                                            <string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
                                            <color key="textColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
                                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                            <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
                                        </textView>
                                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="vto-8g-NOW">
                                            <rect key="frame" x="313" y="11" width="46" height="30"/>
                                            <color key="backgroundColor" red="0.92143100499999997" green="0.92145264149999995" blue="0.92144101860000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                            <state key="normal" title="Button"/>
                                            <connections>
                                                <action selector="didTap:" destination="gZx-b8-Hf3" eventType="touchUpInside" id="4nC-JL-rWD"/>
                                            </connections>
                                        </button>
                                    </subviews>
                                    <constraints>
                                        <constraint firstAttribute="bottomMargin" relation="greaterThanOrEqual" secondItem="vto-8g-NOW" secondAttribute="bottom" id="5P3-E0-KJV"/>
                                        <constraint firstItem="CGL-ug-wBr" firstAttribute="leading" secondItem="xmG-jI-EeI" secondAttribute="leadingMargin" id="6C9-8M-fUa"/>
                                        <constraint firstItem="vto-8g-NOW" firstAttribute="top" secondItem="xmG-jI-EeI" secondAttribute="topMargin" id="Fwc-nY-zK8"/>
                                        <constraint firstAttribute="trailingMargin" secondItem="vto-8g-NOW" secondAttribute="trailing" id="Gfq-Ps-hxG"/>
                                        <constraint firstAttribute="bottomMargin" relation="greaterThanOrEqual" secondItem="CGL-ug-wBr" secondAttribute="bottom" id="PFA-sR-BPk"/>
                                        <constraint firstItem="CGL-ug-wBr" firstAttribute="top" secondItem="xmG-jI-EeI" secondAttribute="topMargin" id="vyi-D5-OSn"/>
                                    </constraints>
                                </tableViewCellContentView>
                                <connections>
                                    <outlet property="textViewHeightConstraint" destination="mK2-jh-d1y" id="jgg-nH-KJ0"/>
                                    <outlet property="theTextView" destination="CGL-ug-wBr" id="GRu-g4-TPK"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="wSO-s3-dB0" id="hW0-YN-O65"/>
                            <outlet property="delegate" destination="wSO-s3-dB0" id="S0F-gf-dAv"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" id="HhZ-lH-fRh"/>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="S7z-u4-GiE" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="357.60000000000002" y="2048.7256371814096"/>
        </scene>
        <!--Navigation Controller-->
        <scene sceneID="PyK-HU-aub">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="9iy-6q-gap" sceneMemberID="viewController">
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="M2B-qr-tr5">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="wSO-s3-dB0" kind="relationship" relationship="rootViewController" id="ghB-H0-NIB"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="AAD-E1-PrO" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-581.60000000000002" y="2048.7256371814096"/>
        </scene>
    </scenes>
</document>

The output looks like this:

enter image description here

When you tap the button in each cell, the text view in that cell will "shrink and fade out" or "grow and fade in".

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • I copied and pasted your code into a test project and it has the same issues. Textview disappears. The only two difference I see in my project is that it is in a stackview and that the action is from didSelect and not a button. Full test project here https://github.com/dpyy/tabletest.git – erotsppa Feb 06 '20 at 23:41
  • @erotsppa - Hmmm.... Did you use my storyboard source? I *believe* the issue is because you have **Scrolling** disabled on your `UITextView`. Re-enable scrolling and see what you get. – DonMag Feb 07 '20 at 02:05
  • Maybe it can behave differently according ios version and simulator or device. – Lukáš Mareda Feb 07 '20 at 08:10
  • @LukášMareda - no, the issue is having scrolling enabled / disabled. If we give the text view a background color, and set the animation duration to 1.5 (nice and slow so we can watch it)... with scrolling **dis**abled the ***text*** disappears while the text **view** shrinks-and-fades. A `UITextView` has a `.textContainer` object which defines the area in which text is displayed. ***That*** object is "snapping" to the new height. Leaving scrolling **en**abled solves this. – DonMag Feb 07 '20 at 13:00
  • It can also be clearly demonstrated by disabling scrolling, but then shrinking the text view's height to, say, 20. We see the `.textContainer` snap to the new height, and then watch the **text view** shrink-and-fade. – DonMag Feb 07 '20 at 13:02