使用半透明分隔线、按钮大小和延迟色调自定义 UIStepper 时出现问题

Problems customizing UIStepper with translucent divider, button sizes and deferring tint color

在为我的 iOS 应用自定义 UIStepper 控件时遇到问题。

到目前为止,我已经能够将其自定义为背景和分隔线是半透明的,并使用下面的代码更改了增量和减量图像...

func decorate(stepper: UIStepper) {
    let greyLeft   = UIImage(named: Assets.Button.leftGrey)
    let greenLeft  = UIImage(named: Assets.Button.leftGreen)
    let greyRight  = UIImage(named: Assets.Button.rightGrey)
    let greenRight = UIImage(named: Assets.Button.rightGreen)
    let blank      = UIImage(named: Assets.Button.translucent)
    let color      = UIColor(red:   147/255,
                             green: 148/255,
                             blue:   81/255,
                             alpha: 1.0)
    
    stepper.setDecrementImage(greenLeft,  for: .normal)
    stepper.setDecrementImage(greyLeft,   for: .disabled)
    stepper.setIncrementImage(greenRight, for: .normal)
    stepper.setIncrementImage(greyRight,  for: .disabled)
    stepper.setBackgroundImage(blank, for: .normal)
    stepper.setDividerImage(blank,
                            forLeftSegmentState: .normal,
                            rightSegmentState: .normal)
    stepper.tintColor = color
}

虽然我有 3 个问题...

  1. 虽然分隔线在正常状态下是半透明的,但当我点击控件时,它似乎会闪烁一个图像。我已经尝试对所有其他可用状态(包括“选定”、“突出显示”、“聚焦”、“禁用”、“应用程序”和“保留”)使用“setDividerImage”方法的第二次调用,但闪光灯仍然存在(见下面的截图)。 如何用我自己的图像替换该图像或防止闪烁?

  1. 即使我使用两个不同的图像(相同的形状,不同的颜色)作为递增和递减图像,它们的原始颜色也会被色调颜色覆盖。我想我可以在色调颜色改变时循环它,但是 是否可以推迟色调颜色以使其不覆盖图像? 然后我可以避免使用纯色。

  2. 我得到的增量图和减图图太小了。 我可以通过编程方式调整大小吗? 这样我就不必编辑图像或返回到我的图形艺术家处获得更大的图像。

问题#1 是我最关心的问题,因为我认为如果需要我可以处理#2 和#3。但是,如果我至少能确认这些问题的答案是“否”,那就太好了。

更改此行:

let blank = UIImage(named: Assets.Button.translucent)

至:

let blank = UIImage()

应该去掉突出显示的分隔符。

如果您的图像是简单的箭头,您可以通过代码“即时”轻松生成具有所需颜色的箭头,或将它们用作可着色图像。

如果你像这样加载图像:

let greyLeft   = UIImage(named: Assets.Button.leftGrey)?.withRenderingMode(.alwaysOriginal)
let greenLeft  = UIImage(named: Assets.Button.leftGreen)?.withRenderingMode(.alwaysOriginal)
let greyRight  = UIImage(named: Assets.Button.rightGrey)?.withRenderingMode(.alwaysOriginal)
let greenRight = UIImage(named: Assets.Button.rightGreen)?.withRenderingMode(.alwaysOriginal)

它们不应受到色调颜色的影响。


编辑

看看这些变化:

func decorate(stepper: UIStepper) {
    
    let colorNormal         = UIColor(red:   147/255,
                                      green: 148/255,
                                      blue:   81/255,
                                      alpha: 1.0)
    
    let colorHighlighted    = UIColor(red:   0.9,
                                      green: 0.0,
                                      blue:   0.0,
                                      alpha: 1.0)
    
    let colorDisabled       = UIColor(red:   0.25,
                                      green: 0.25,
                                      blue:   0.25,
                                      alpha: 1.0)
    
    // adjust size to your liking
    let fnt = UIFont.systemFont(ofSize: 32)
    let configuration = UIImage.SymbolConfiguration(font: fnt)
    
    let lArrow              = UIImage(systemName: "arrowtriangle.left.fill", withConfiguration: configuration)?.withRenderingMode(.alwaysOriginal)
    let leftNormal          = lArrow?.withTintColor(colorNormal)
    let leftHighlighted     = lArrow?.withTintColor(colorHighlighted)
    let leftDisabled        = lArrow?.withTintColor(colorDisabled)

    let rArrow              = UIImage(systemName: "arrowtriangle.right.fill", withConfiguration: configuration)?.withRenderingMode(.alwaysOriginal)
    let rightNormal         = rArrow?.withTintColor(colorNormal)
    let rightHighlighted    = rArrow?.withTintColor(colorHighlighted)
    let rightDisabled       = rArrow?.withTintColor(colorDisabled)
    
    let blank               = UIImage()

    stepper.setDecrementImage(leftNormal, for: .normal)
    stepper.setDecrementImage(leftHighlighted, for: .highlighted)
    stepper.setDecrementImage(leftDisabled, for: .disabled)

    stepper.setIncrementImage(rightNormal, for: .normal)
    stepper.setIncrementImage(rightHighlighted, for: .highlighted)
    stepper.setIncrementImage(rightDisabled, for: .disabled)
    
    stepper.setBackgroundImage(blank, for: .normal)
    stepper.setDividerImage(blank,
                            forLeftSegmentState: .normal,
                            rightSegmentState: .normal)

}

这使用左右填充三角形 SF Symbol 图像(根据您的喜好调整大小),并且我为 Highlighted 状态添加了颜色(不需要)。


编辑 2

如果你想在 dec/inc 按钮之间添加一些水平的 space,我们可以通过使用清晰的图像作为“分隔线”图像来实现——但是,Apple 的文档并不特别清楚如何去做。

为了避免按钮之间的“奇怪的突出显示”,我们必须为 3 个“状态组合”设置清晰的图像:

normal / normal
normal / highlighted
highlighted / normal

所以,如果我们想要,例如,64 点的水平间距:

    // create a clear image of desired width
    //  (height will be auto-stretched)
    let blank = UIGraphicsImageRenderer(size: CGSize(width: 64, height: 8)).image(actions: {c in})

    stepper.setBackgroundImage(blank, for: .normal)

    // set blank image for normal / normal
    stepper.setDividerImage(blank,
                            forLeftSegmentState: .normal,
                            rightSegmentState: .normal)

    // set blank image for normal / highlighted
    stepper.setDividerImage(blank,
                            forLeftSegmentState: .normal,
                            rightSegmentState: .highlighted)

    // set blank image for highlighted / normal
    stepper.setDividerImage(blank,
                            forLeftSegmentState: .highlighted,
                            rightSegmentState: .normal)

我们必须至少设置这 3 个状态组合。

奇怪的是,如果一个(或两个)按钮是 .disabled,我们还可以设置要使用的图像...但是,如果我们不这样做它使用匹配的 .normal 状态。

注意: 使用自定义宽度分隔图像会压缩按钮的宽度,因此这可能是也可能不是有用的信息。