问题 有没有办法动画更改UILabel的textAlignment?


我正在使用iOS 7,我正在尝试移动一个位于视图左侧中心的标签。目前我试图通过改变我的UILabel的对齐方式来做到这一点,并且我正在尝试在此过程中为其设置动画。我目前正在呼吁以下内容:

[UIView animateWithDuration:0.5
                 animations:^{
                      self.monthLabel.textAlignment = NSTextAlignmentLeft;
                 } completion:nil];

但这只是将标签跳转到新的对齐方式。有没有办法动画这个,或者更好的方法来调整标签以实现这一目标?


2329
2017-10-08 15:09


起源



答案:


将UILabel框架大小设置为精确包含文本并将UILabel置于视图中心。

self.monthLabel.text = @"February";
[self.monthLabel sizeToFit];
self.monthLabel.center = parentView.center; // You may need to adjust the y position

然后设置不应影响布局的对齐,因为没有额外的空间。

self.monthLabel.textAlignment = NSTextAlignmentLeft;

接下来,为UILabel框架大小设置动画,使其滑过您想要的位置。

[UIView animateWithDuration:0.5
             animations:^{
                  CGRect frame = self.monthLabel.frame;
                  frame.origin.x = 10;
                  self.monthLabel.frame = frame;
             } completion:nil];

10
2017-10-08 15:18



我无法将框架设置为我的标签的确切大小,因为文本将会更改,特别是使用不同月份的名称 - lehn0058
在设置文本的同时更新标签框。我更新了答案以说明如何执行此操作。 - bbarnhart
@bbarnhart如果标签中有2行文字怎么办?比这还行不通...... - Boris Nikolić
这应该。什么部分不起作用? - bbarnhart


答案:


将UILabel框架大小设置为精确包含文本并将UILabel置于视图中心。

self.monthLabel.text = @"February";
[self.monthLabel sizeToFit];
self.monthLabel.center = parentView.center; // You may need to adjust the y position

然后设置不应影响布局的对齐,因为没有额外的空间。

self.monthLabel.textAlignment = NSTextAlignmentLeft;

接下来,为UILabel框架大小设置动画,使其滑过您想要的位置。

[UIView animateWithDuration:0.5
             animations:^{
                  CGRect frame = self.monthLabel.frame;
                  frame.origin.x = 10;
                  self.monthLabel.frame = frame;
             } completion:nil];

10
2017-10-08 15:18



我无法将框架设置为我的标签的确切大小,因为文本将会更改,特别是使用不同月份的名称 - lehn0058
在设置文本的同时更新标签框。我更新了答案以说明如何执行此操作。 - bbarnhart
@bbarnhart如果标签中有2行文字怎么办?比这还行不通...... - Boris Nikolić
这应该。什么部分不起作用? - bbarnhart


你的标签是多线的吗?像这样的动画: http://img62.imageshack.us/img62/9693/t7hx.png

如果是这样,那么有几种选择。

多行标签

选项1:

而不是传统的UIView动画,尝试UIView过渡。文本不会向左滑动,而是会很好地淡化到新位置。

[UIView transitionWithView:self.monthLabel
                      duration:0.5
                       options:UIViewAnimationOptionTransitionCrossDissolve
                    animations:^{
        self.monthLabel.textAlignment = NSTextAlignmentLeft;
    } completion:NO];

选项2:

您可以手动计算出现新行的位置,然后为每行文本创建单独的UILabel,然后为帧设置动画。这显然是更多的工作,但会给出所需的幻灯片动画。

单行标签

而不是动画textAlignment,使标签与其包含的字符串大小相同 [self.monthLabel sizeToFit],然后手动计算框架和居中。然后只需为框架设置动画,与多行标签上的选项2相同。


3
2017-10-09 00:01





您可以为FRAME设置动画,而不是textAlignment。

如果你想摆脱框架上的任何“填充”,你可以在你的标签上做一个[UILabel sizeToFit],然后你就可以动画动画块中的框架动画来移动它你想要的

CGRect frameLabel = self.monthLabel.frame;

[UIView animateWithDuration:0.5
                 animations:^{
                      frameLabel.origin.x -= 100;          // e.g. move it left by 100
                      self.monthLabel.frame = frameLabel;
                 } completion:nil];

1
2017-10-08 15:14



我喜欢这种方法!我需要让我的标签居中(现在它显示日历集合视图上方一个月的名称)所以我将使用它并初步设置标签的中心而不是尝试使用textAlignment - lehn0058
如果要在块动画中设置变量“frameLabel”,则需要使用访问前缀“__block CGRect frameLabel”设置变量...,因为您将更改块中的值变量frameLabel。 - horkavlna


你只需要为你的标签框架制作动画。 因为这里有完成块,你应该再次更改框架。并使循环进行。

[UIView animateWithDuration:0.5
                 animations:^{
                      // Change the frame
                 } completion:^{[UIView animateWithDuration:0.5
                 animations:^{
                      // Change the frame
                 } completion:^{
                     // repeat the proccess
}]

}];

0
2017-10-08 15:16



我会的,但我在标签的两边都有填充,因为我的文字会根据用户选择的月份而改变。 - lehn0058


这对我有好处

import Foundation
import UIKit


class AnimatableMultilineLabel: UIView {

    enum Alignment {
        case left
        case right
    }

    public var textAlignment: Alignment = .left {
        didSet {
            layout()
        }
    }

    public var font: UIFont? = nil {
        didSet {
            setNeedsLayout()
        }
    }

    public var textColor: UIColor? = nil {
        didSet {
            setNeedsLayout()
        }
    }

    public var lines: [String] = [] {
        didSet {
            for label in labels {
                label.removeFromSuperview()
            }
            labels = []
            setNeedsLayout()
        }
    }

    private var labels: [UILabel] = []

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    private func setup() {
        isUserInteractionEnabled = false
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        layout()
    }

    private func layout() {

        autocreateLabels()

        var yPosition: CGFloat = 0.0
        for label in labels {
            let size = label.sizeThatFits(bounds.size)
            let minX = textAlignment == .left ? 0.0 : bounds.width - size.width
            let frame = CGRect(x: minX, y: yPosition, width: size.width, height: size.height)
            label.frame = frame
            yPosition = frame.maxY
        }
    }

    private func autocreateLabels() {
        if labels.count != lines.count {
            for text in lines {
                let label = UILabel()
                label.font = font
                label.textColor = textColor
                label.text = text
                addSubview(label)
                labels.append(label)
            }
        }
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        autocreateLabels()

        var height: CGFloat = 0.0
        for label in labels {
            height = label.sizeThatFits(size).height
        }
        return CGSize(width: size.width, height: height)
    }
}

那么你应该可以

UIView.animate(withDuration: 0.5, animations: {
    multilineLabel.textAlignment = .right
})

0
2017-12-18 14:53



有趣。你如何决定分手? - agibson007
所有的线都没有破,所以我事先知道我可以用这种方式宣布它。更智能的解决方案将采用属性字符串并自动为换行设置正确的动画。 - hfossli