我正在try 使用CollectionViewCell创建自定义段控件.所以我可以在不同的设备中管理段控件的文本大小.但并非所有设备都能正常工作.

这是sizeForItemAt的密码

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: (collectionView.frame.width / 3), height: 50.0)
}

Here is the output that i am getting This is output in iPhone 8. Title is not properly visible

This is output in iPhone 12 Pro Max

所以我试图找到一个解决方案,使用它我可以管理所有设备中的文本大小,所有单元格也可以采用相同的间距.

推荐答案

下面是我能想到的一种方法,但绝不是唯一的方法.

首先,我设置了一个带有水平流布局的集合视图.

// Flow layout configuration, mainly to figure out width of the cells
private func createLayout() -> UICollectionViewFlowLayout {
    
    let flowLayout = UICollectionViewFlowLayout()
    flowLayout.minimumLineSpacing = horizontalPadding
    flowLayout.minimumInteritemSpacing = 0
    flowLayout.scrollDirection = .horizontal
    
    // Calculate the available width to divide the segments evenly
    var availableWidth = UIScreen.main.bounds.width
    
    // There will always be segments - 1 gaps, for 3 segments, there will be
    // 2 gaps and for 4 segments there will be 3 gaps etc
    availableWidth -= horizontalPadding * CGFloat(segments.count - 1)
    
    let cellWidth = availableWidth / CGFloat(segments.count)
    
    flowLayout.itemSize = CGSize(width: cellWidth,
                                 height: collectionViewHeight)
    
    return flowLayout
}

一旦我这么做了,我就会遇到同样的问题,根据屏幕的宽度,我的文本可能会被切断.

UICollectionView UISegmentController UICollectionViewCell custom swift iOS

所以一旦确定了每段的宽度,我们就必须计算出maximum font size to show the complete text for the longest segment and that font size should be applied to all

在这种情况下,长段的字符串长度为Vibration Intensity.

// Flow layout configuration, mainly to figure out width of the cells
private func createLayout() -> UICollectionViewFlowLayout {
    
    let flowLayout = UICollectionViewFlowLayout()
    flowLayout.minimumLineSpacing = horizontalPadding
    flowLayout.minimumInteritemSpacing = 0
    flowLayout.scrollDirection = .horizontal
    flowLayout.sectionInset = UIEdgeInsets(top: 0,
                                           left: horizontalPadding,
                                           bottom: 0,
                                           right: horizontalPadding)
    
    // Calculate the available width to divide the segments evenly
    var availableWidth = UIScreen.main.bounds.width
    
    // There will always be segments - 1 gaps, for 3 segments, there will be
    // 2 gaps and for 4 segments there will be 3 gaps etc
    availableWidth -= horizontalPadding * CGFloat(segments.count - 1)
    
    // Remove the insets
    availableWidth -= flowLayout.sectionInset.left + flowLayout.sectionInset.right
    
    let cellWidth = availableWidth / CGFloat(segments.count)
    
    // Add this function
    calculateApproxFontSize(forWidth: cellWidth)
    
    flowLayout.itemSize = CGSize(width: cellWidth,
                                 height: collectionViewHeight)
    
    return flowLayout
}

private func calculateApproxFontSize(forWidth width: CGFloat) {
    
    // Get the longest segment by length
    if let longestSegmentTitle = segments.max(by: { $1.count > $0.count }) {
        
        let tempLabel = UILabel()
        tempLabel.numberOfLines = 1
        tempLabel.text = longestSegmentTitle
        tempLabel.sizeToFit()
        
        guard var currentFont = tempLabel.font else { return }
        
        var intrinsicSize
            = (longestSegmentTitle as NSString).size(withAttributes: [.font : currentFont])
        
        // Keep looping and reduce the font size till the text
        // fits into the label
        // This could be optimized further using binary search
        // However this should be ok for small strings
        while intrinsicSize.width > width
        {
            currentFont = currentFont.withSize(currentFont.pointSize - 1)
            tempLabel.font = currentFont
            
            intrinsicSize
                = (longestSegmentTitle as NSString).size(withAttributes: [.font : currentFont])
        }

        // Set the font of the current label
        // segmentFontSize is a global var in the VC
        segmentFontSize = currentFont.pointSize
    }
}

然后在cellForItemAt indexPath中设置segmentFontSize

func collectionView(_ collectionView: UICollectionView,
                    cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
    let cell = collectionView
        .dequeueReusableCell(withReuseIdentifier: SegmentCell.reuseIdentifier,
                             for: indexPath) as! SegmentCell
    
    cell.backgroundColor = .orange
    cell.title.text = segments[indexPath.item]
    
    // Adjust the font
    cell.title.font = cell.title.font.withSize(segmentFontSize)
    
    return cell
}

这会给你类似的东西:

Resize UILabel to fit frame rect in swift iOS using UICollectionView as UISegmentView

如果你发现某些部分很难理解,下面是完整代码的链接:https://gist.github.com/shawn-frank/03bc06d13f90a54e23e9ea8c6f30a70e

Ios相关问答推荐

iPhone:iOS 17.4中没有气压数据

UIBezierPath包含:方法不检测到厚度大于1像素的线上的touch

如何让3张组合的`SF Symbol`图片围绕一个特定点旋转?

使用AVCaptureEventInteraction捕获音量按键快门

ios PWA从外部链接返回后降低了innerheight

clang:错误:SDK 路径中不包含libarclite

Strange UIView.animate更改UIButton标题 colored颜色 的行为

如何在 SwiftUI 视图中显示协议视图?

如何根据条件快速将返回类型设为 LinearGradient 或 AngularGradient?

SwiftUI DatePicker 格式在每个设备上都不一样,如何让它总是显示相同的 Select 版本?

向左或向右移动时如何水平翻转sprite?

如何在保持纵横比的同时zoom UIView 的内容以适应目标矩形?

如何找出坐标之间的距离?

在代码生成的 UIView 上绘制 UIBezierPath

在 Xcode 5 中为超级视图添加间距约束

在 iOS 7 上更改标签栏色调 colored颜色

如何在键盘上方添加工具栏?

Sierra 中的安全/协同设计: keys 串忽略访问控制设置和 UI 提示权限

判断从 JSON 字符串返回的 Objective-C 中的空值

UITableView 中的圆形 UIImageView 没有性能影响?