Xcode: AccessoryType.checkmark pushes other views to the left

ぐ巨炮叔叔 提交于 2021-01-29 10:23:07

问题


Xcode 10, Swift 5, iOS 12

My app contains 3 ViewControllers:

  1. Login
  2. TableView
  3. Detailed info about data of single row in TableView

If you edit and save the data in ViewController 3 and use the "back" button (through a NavigationController) to go back to ViewController 2, a checkmark is added to the corresponding row in the TableView.

The problem is that this checkmark pushes everything else to the left, even though I left some space for it:

Setup:

  • Horizontal StackView with 2 subviews with 1 label each
  • The StackView is set to "Fill"
  • The second subview is half as wide as the first one
  • 10 pts leading on the left and 40pts trailing on the right (also already tested with 100pts but no change)

I already tried adding an AccessoryType.none to each row (as suggested here) when I create them - like this:

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
    cell.setLabels("Label1","Label2")
    tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.none
    //cell.accessoryType = UITableViewCell.AccessoryType.none //This doesn't work either

    return cell
}

but it doesn't get added (same thing with the other types).

How do I fix this? Is it possible to set the checkmark "behind" everything else while still using an AccessoryType?


回答1:


Inside your UITableViewCell you created to handle the cell add the following function. This function tests if this current cell has an accessoryType set and if not then it makes the cell 40pts smaller, thus making the cells with and without accessory the same size for the auto layout.

override var frame: CGRect {
    get {
        return super.frame
    }
    set (newFrame) {
        var frame = newFrame
        if self.accessoryType == .none {
            frame.size.width -= 40
        }
        super.frame = frame
    }
}



回答2:


There are a number of approaches to this, but I think the best approach is to add an image view to your custom cell and use your own checkmark image.

Then when you set the labels' text in cellForRowAt, instead of setting cell.accessoryType = .checkmark where needed, set the image of the image view to your own checkmark image (or, set the image view .alpha to 0 (not shown) or 1 (shown)):

Of course, you'd use your own much better checkmark image than the one I grabbed for this example :)

Edit:

If you want to use a tint color, you can set your image to a "template" image. Something like this in your cell init:

    checkImageView.image = checkImageView.image?.withRenderingMode(.alwaysTemplate)
    checkImageView.tintColor = .red

Edit 2:

If you don't want to use a custom image, you can constrain your stack view's trailing edge to the Cell instead of to the cell's Content View:

40-pts looks about right, but you'd want to confirm that, and you'd want to double-check that the spacing is the same on different devices (retina vs. non-retina, etc).

Also, the proper way to set the accessory is to set it on the cell in cellForRowAt. Assuming (based on your comments) that you are keeping a reference to the selected row - let's say it's

var currentSelectedIndexPath: IndexPath!

You want to do something similar to this:

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

    let cell = tableView.dequeueReusableCell(withIdentifier: "MyCustomCell", for: indexPath) as! MyCustomCell

    cell.leftLabel.text = "Left \(indexPath.row)"
    cell.rightLabel.text = "Right \(indexPath.row)"

    cell.accessoryType = (indexPath == currentSelectedIndexPath) ? .checkmark : .none

    return cell

}

Edit 3:

You need to do some more reading on table views, cells, selections, data tracking, etc...

But, here is a complete example for you.

First, the Storyboard. Create a new single-view project. Right-click on the Storyboard and select

Open As -> Source Code

Delete what's there, and paste in the following:

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="KbA-Q0-LNC">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Selected Row Table View Controller-->
        <scene sceneID="DAq-F3-sy8">
            <objects>
                <tableViewController id="qt8-QK-wnn" customClass="SelectedRowTableViewController" customModule="XC10SWScratch" 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="2Gh-42-LWt">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                        <prototypes>
                            <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="MyCustomCell" rowHeight="56" id="r8I-XK-VkK" customClass="MyCustomCell" customModule="XC10SWScratch" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="28" width="375" height="56"/>
                                <autoresizingMask key="autoresizingMask"/>
                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="r8I-XK-VkK" id="MvA-eu-x6f">
                                    <rect key="frame" x="0.0" y="0.0" width="375" height="55.5"/>
                                    <autoresizingMask key="autoresizingMask"/>
                                    <subviews>
                                        <stackView opaque="NO" contentMode="scaleToFill" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="mQ2-DJ-vUS">
                                            <rect key="frame" x="10" y="0.0" width="325" height="55.5"/>
                                            <subviews>
                                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bfe-Sh-FxV">
                                                    <rect key="frame" x="0.0" y="0.0" width="210" height="55.5"/>
                                                    <subviews>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label 1" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hhj-4f-3ME">
                                                            <rect key="frame" x="10" y="10" width="190" height="35.5"/>
                                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                    </subviews>
                                                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                    <constraints>
                                                        <constraint firstItem="Hhj-4f-3ME" firstAttribute="top" secondItem="bfe-Sh-FxV" secondAttribute="top" constant="10" id="BXa-Av-XMu"/>
                                                        <constraint firstAttribute="trailing" secondItem="Hhj-4f-3ME" secondAttribute="trailing" constant="10" id="ND3-SS-NJN"/>
                                                        <constraint firstItem="Hhj-4f-3ME" firstAttribute="leading" secondItem="bfe-Sh-FxV" secondAttribute="leading" constant="10" id="fhX-ir-pnY"/>
                                                        <constraint firstAttribute="bottom" secondItem="Hhj-4f-3ME" secondAttribute="bottom" constant="10" id="jCn-Ib-SDq"/>
                                                    </constraints>
                                                </view>
                                                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ydx-kR-Ui2">
                                                    <rect key="frame" x="220" y="0.0" width="105" height="55.5"/>
                                                    <subviews>
                                                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label 2" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vaR-rB-U1a">
                                                            <rect key="frame" x="10" y="10" width="85" height="35.5"/>
                                                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                            <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                                            <nil key="textColor"/>
                                                            <nil key="highlightedColor"/>
                                                        </label>
                                                    </subviews>
                                                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                                    <constraints>
                                                        <constraint firstItem="vaR-rB-U1a" firstAttribute="top" secondItem="ydx-kR-Ui2" secondAttribute="top" constant="10" id="5LB-SK-csH"/>
                                                        <constraint firstAttribute="bottom" secondItem="vaR-rB-U1a" secondAttribute="bottom" constant="10" id="ghm-bd-7PC"/>
                                                        <constraint firstAttribute="trailing" secondItem="vaR-rB-U1a" secondAttribute="trailing" constant="10" id="rIn-3p-Lpj"/>
                                                        <constraint firstItem="vaR-rB-U1a" firstAttribute="leading" secondItem="ydx-kR-Ui2" secondAttribute="leading" constant="10" id="z1q-yz-bd6"/>
                                                    </constraints>
                                                </view>
                                            </subviews>
                                            <constraints>
                                                <constraint firstItem="ydx-kR-Ui2" firstAttribute="width" secondItem="bfe-Sh-FxV" secondAttribute="width" multiplier="0.5" id="4h1-AF-V9L"/>
                                            </constraints>
                                        </stackView>
                                    </subviews>
                                    <constraints>
                                        <constraint firstItem="mQ2-DJ-vUS" firstAttribute="top" secondItem="MvA-eu-x6f" secondAttribute="top" id="HNe-Ks-vip"/>
                                        <constraint firstItem="mQ2-DJ-vUS" firstAttribute="leading" secondItem="MvA-eu-x6f" secondAttribute="leading" constant="10" id="RCj-FT-gww"/>
                                        <constraint firstAttribute="bottom" secondItem="mQ2-DJ-vUS" secondAttribute="bottom" id="azO-kX-4jB"/>
                                    </constraints>
                                </tableViewCellContentView>
                                <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
                                <constraints>
                                    <constraint firstAttribute="trailing" secondItem="mQ2-DJ-vUS" secondAttribute="trailing" constant="40" id="UCo-0w-3ki"/>
                                </constraints>
                                <connections>
                                    <outlet property="leftLabel" destination="Hhj-4f-3ME" id="WQS-bJ-KeJ"/>
                                    <outlet property="rightLabel" destination="vaR-rB-U1a" id="RXC-UG-g5P"/>
                                </connections>
                            </tableViewCell>
                        </prototypes>
                        <connections>
                            <outlet property="dataSource" destination="qt8-QK-wnn" id="aMA-fV-5cb"/>
                            <outlet property="delegate" destination="qt8-QK-wnn" id="S0n-bN-MLJ"/>
                        </connections>
                    </tableView>
                    <navigationItem key="navigationItem" id="kxZ-av-xIt"/>
                </tableViewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="qxa-2p-Cxd" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="1556" y="830.73463268365822"/>
        </scene>
        <!--Navigation Controller-->
        <scene sceneID="d0B-12-bYa">
            <objects>
                <navigationController automaticallyAdjustsScrollViewInsets="NO" id="KbA-Q0-LNC" sceneMemberID="viewController">
                    <toolbarItems/>
                    <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="jcB-K3-ueL">
                        <rect key="frame" x="0.0" y="20" width="375" height="44"/>
                        <autoresizingMask key="autoresizingMask"/>
                    </navigationBar>
                    <nil name="viewControllers"/>
                    <connections>
                        <segue destination="qt8-QK-wnn" kind="relationship" relationship="rootViewController" id="YsO-wj-izb"/>
                    </connections>
                </navigationController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="5gD-zl-juz" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="616.79999999999995" y="830.73463268365822"/>
        </scene>
    </scenes>
</document>

You can then Right-click on the Storyboard and select

Open As -> Interface Builder - Storyboard

to view the layout.

Next, replace the contents of the default ViewController.swift with this code:

import UIKit

class MyCustomCell: UITableViewCell {

    @IBOutlet var leftLabel: UILabel!
    @IBOutlet var rightLabel: UILabel!

}

class SelectedRowTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.estimatedRowHeight = 60.0
    }

    // MARK: - Table view data source
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

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

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath)
        cell?.accessoryType = .checkmark
    }

    override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath)
        cell?.accessoryType = .none
    }

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

        let cell = tableView.dequeueReusableCell(withIdentifier: "MyCustomCell", for: indexPath) as! MyCustomCell

        cell.leftLabel.text = "Left \(indexPath.row)"
        cell.rightLabel.text = "Right \(indexPath.row)"

        cell.accessoryType = (tableView.indexPathForSelectedRow == indexPath) ? .checkmark : .none

        return cell

    }

}

You should then be able to run the app. Inspect the constraints on the custom cell, and review the code (very, very basic) to see how the checkmark is set on the selected row (and removed on the unselected row), and how it is set correctly when scrolling.



来源:https://stackoverflow.com/questions/55746309/xcode-accessorytype-checkmark-pushes-other-views-to-the-left

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!