【问题标题】:UIView doesn't animate horizontally from right to leftUIView 不会从右到左水平动画
【发布时间】:2016-07-17 17:43:41
【问题描述】:

我在水平的UIStackView 中有两个UIButtons。我想添加一个UIView 作为子视图,这样当我按下其中一个按钮时,视图会水平移动到所选按钮。

我有这个代码:

let selectionView = UIView(frame: CGRect(x: 0, y: 0, width: 70, height: 19))
selectionView.backgroundColor = UIColor.greenColor()
self.incomeButton.addSubview(selectionView) // left button


// left button touched
@IBAction func incomeDidTouch(sender: AnyObject) {
    self.incomeButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    self.expensiveButton.setTitleColor(UIColor.grayColor(), forState: .Normal)

    UIView.animateWithDuration(0.3) {
        self.selectionView.backgroundColor = UIColor.greenColor()
        self.selectionView.center = self.incomeButton.center
    }
}

// right button touched   
@IBAction func expensiveDidTouch(sender: AnyObject) {
    self.expensiveButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
    self.incomeButton.setTitleColor(UIColor.grayColor(), forState: .Normal)

    UIView.animateWithDuration(0.3) {
        self.selectionView.backgroundColor = UIColor.redColor()
        self.selectionView.center = self.expensiveButton.center
    }

当视图添加到左侧按钮时,此代码实际上可以工作。单击按钮时,视图将从左向右和从右向左移动。

但如果我从选择右键开始:

    let selectionView = UIView(frame: CGRect(x: 0, y: 0, width: 70, height: 19))
    selectionView.backgroundColor = UIColor.redColor()
    self.expensiveButton.addSubview(selectionView)  // right button

视图只改变颜色,但不会从右向左移动。

这是为什么呢?如何修复我的代码以便视图可以移动?

UPDATE

我尝试在 UIView 中添加堆栈视图,并在其中添加 selectionView。这是一张快照:

当我在选择右键运行应用程序时仍然遇到问题,selectionView 出现在 containerView 之外(它应该出现在 Expensive 文本的右侧):

当我检查应该选择哪个按钮时,这是viewDidLoad 中的代码:

if type == .Income {
    self.selectionView.backgroundColor = UIColor(hex: "28BB9D")
    self.selectionView.center = self.incomeButton.center
} else {
    self.selectionView.backgroundColor = UIColor(hex: "E5344A")
}

UPDATE 2:

selectionView 的当前约束:

【问题讨论】:

    标签: ios swift


    【解决方案1】:

    目标

    以编程方式创建一个selectionView,以便在小时候切换两个UIButton

    为了更好地解释我已经添加(开始)selectionViewexpensiveButton(您遇到问题的按钮..)的情况

    您可以在项目中进行一些更正以使其正常运行。

    class ViewController: UIViewController {
        @IBOutlet weak var stackView: UIStackView!
        @IBOutlet weak var incomeButton: UIButton!
        @IBOutlet weak var expensiveButton: UIButton!
        var selectionView : UIView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            selectionView = UIView(frame: CGRect(x: 0, y: 0, width: 70, height: 19))
            selectionView.backgroundColor = UIColor.greenColor()
            selectionView.tag = 666
        }
        override func viewDidAppear(animated: Bool) {
            super.viewDidAppear(animated)
            self.expensiveButton.addSubview(selectionView)
            self.selectionView.backgroundColor = UIColor.redColor()
            self.selectionView.center = CGPointMake(self.expensiveButton.bounds.midX, self.expensiveButton.bounds.midY)
        }
        @IBAction func incomeDidTouch(sender: AnyObject) {
            if let _ = sender.viewWithTag(666) {} else {
                self.incomeButton.addSubview(selectionView)
            }
            self.expensiveButton.viewWithTag(666)?.removeFromSuperview()
            self.incomeButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
            self.expensiveButton.setTitleColor(UIColor.grayColor(), forState: .Normal)
    
            UIView.animateWithDuration(0.3) {
                self.selectionView.backgroundColor = UIColor.greenColor()
                self.selectionView.center = CGPointMake(self.incomeButton.bounds.midX, self.incomeButton.bounds.midY)
            }
        }
        @IBAction func expensiveDidTouch(sender: AnyObject) {
            if let _ = sender.viewWithTag(666) {} else {
                self.expensiveButton.addSubview(selectionView)
            }
            self.incomeButton.viewWithTag(666)?.removeFromSuperview()
            self.expensiveButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
            self.incomeButton.setTitleColor(UIColor.grayColor(), forState: .Normal)
    
            UIView.animateWithDuration(0.3) {
                self.selectionView.backgroundColor = UIColor.redColor()
                self.selectionView.center = CGPointMake(self.expensiveButton.bounds.midX, self.expensiveButton.bounds.midY)
            }
        }
    }
    

    一些解释

    首先,在您的项目中,您没有报告对selectView 的全局引用,但我认为您只是忘记在问题中写下它。

    因此,最好为您的 selectionView 设置一个标签,例如一个 ID 号,以便在他未来的父视图的子视图之间识别它(在您的情况下,它将是 UIButton

    如您所见,我添加了viewDidAppear 方法,为什么?因为当你在viewDidLoad 时,你的按钮还没有完全准备好,所以你有一个错误的中心,当你的视图最终被绘制时,这个值的正确位置是viewDidAppear

    现在让我们谈谈selectionView:它是一个视图,因此您可以将其添加到incomeButton,但如果您已经在另一个按钮中添加了它,则必须使用以下行将其从昂贵按钮中删除:

    self.expensiveButton.viewWithTag(666)?.removeFromSuperview()
    

    最后是中心点:记住你是在自动布局中,所以找到它的好方法可能是使用边界:

    self.selectionView.center = CGPointMake(self.expensiveButton.bounds.midX, self.expensiveButton.bounds.midY)
    

    这是我的项目结构,我看到你正在处理它:

    更新

    在我看到您的更新(您从以编程方式创建的 selectionView 开始)一些 cmets 并回答您的问题后,我怀疑您想要实现自定义 UISegmentedControl。我认为使用UIStackView 来实现类似的小控制不是一个好主意,您可以在UISegmentedControl 周围找到许多项目UIControl 子类,例如BetterSegmentedControl

    代码示例

    let control = BetterSegmentedControl(
        frame: CGRect(x: 0.0, y: 100.0, width: view.bounds.width, height: 44.0),
        titles: ["One", "Two", "Three"],
        index: 1,
        backgroundColor: UIColor(red:0.11, green:0.12, blue:0.13, alpha:1.00),
        titleColor: .whiteColor(),
        indicatorViewBackgroundColor: UIColor(red:0.55, green:0.26, blue:0.86, alpha:1.00),
        selectedTitleColor: .blackColor())
    control.titleFont = UIFont(name: "HelveticaNeue", size: 14.0)!
    control.selectedTitleFont = UIFont(name: "HelveticaNeue-Medium", size: 14.0)!
    control.addTarget(self, action: #selector(ViewController.controlValueChanged(_:)), forControlEvents: .ValueChanged)
    view.addSubview(control)
    

    一张图片

    【讨论】:

    • 如果你愿意,你可以在这里下载这个项目:s000.tinyupload.com/?file_id=63536169362592196504
    • 我这样做了,因为我想为从一个按钮到另一个按钮的滑动 (selectionView) 设置动画
    • 如你所见,segmentedControl更能实现你想要的。在我的回答中,我过去使用过这个自定义库,它在幻灯片期间有很好的效果。但是,您可以尝试开发您的自定义对象,但不能使用 stackView..
    • 是的,我想我会选择这个。谢谢。
    • 也谢谢科比,我很高兴能提供帮助。
    【解决方案2】:

    这里的关键问题是坐标系。您将 selectionView 添加为一个按钮或另一个按钮的子视图,但由于它在两者之间移动,它实际上应该是两个按钮的某些祖先视图的子视图。

    当您更改 selectionView 中心时,它会将其位置 相对于其父视图设置动画,在您当前的代码中,该位置是左按钮或右按钮。从左到右的动画是可行的,因为右按钮的中心是某个坐标,其 x 值大于左按钮坐标空间内的 selectionView 的 x 值。但是当你从右键坐标空间内的 selectionView 开始时,左键的中心相对于它自己的父视图可能非常接近 selectionView 的中心相对于右键的坐标空间时间>。所以没有任何真正的运动。

    如果你这样想,这可能更容易可视化:为了从右侧按钮的坐标空间内移动到左侧按钮所在的位置,selectionView 的中心 x 需要为负数,因为它会需要位于右侧按钮前沿的左侧。然而,左按钮的中心相对于它自己的 superview 有一个正的 x 值。所以将 selectionView 的中心设置为左按钮的中心,如果它在右按钮的坐标空间内,将永远不会让它向左移动。

    通过将选择视图添加到两个按钮所在的同一个超级视图中,您可以成功使用动画中的中心坐标,因为所有三个视图(2 个按钮和 selectionView)都将位于同一坐标空间中。

    如果 2 个按钮位于堆栈视图中,这可能会有点混乱,因为您不想手动为堆栈视图排列的内容设置动画。在这种情况下,解决方案是将堆栈视图包装在普通 UIView 中,并将 selectionView 添加到堆栈视图的前面,作为同一普通 UIView 的子视图。

    只要堆栈视图框架与包含 UIView 的边界匹配,它仍然可以很好地在左按钮中心和右按钮中心之间为 selectionView 的中心设置动画。

    TLDR;

    使用以下视图层次结构,您的代码将起作用:

    containerView
          |____ selectionView
          |____ stackView
                    |_______ leftButton
                    |_______ rightButton
    

    【讨论】:

    • 我尝试了您的建议,但仍有问题。我已经用我所做的更新了我的问题。
    • @Kobe 在您的更新中,如果选择了收入按钮,我看到了移动 selectionView 中心以匹配收入按钮中心的代码,但我没有看到将 selectedView 的中心移动到的代码else 案例中昂贵按钮的中心。此外,您的屏幕截图中的 selectedView 看起来它的中心等于昂贵按钮的 origin 而不是它的中心
    【解决方案3】:

    这是我的解决方案。 我做了以下视图和约束安排:

    选择视图有以下限制:

    在 4 个约束中,第一个约束(Align Center X to Stack View)与视图控制器无关。 总网点如下:

    @IBOutlet weak var stackView: UIStackView!
    @IBOutlet weak var selectionView: UIView!
    @IBOutlet weak var selectionviewCenterCon: NSLayoutConstraint!
    @IBOutlet weak var expensiveBtn: UIButton!
    @IBOutlet weak var incomeBtn: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.selectionView.backgroundColor = UIColor.redColor()
        self.selectionviewCenterCon.constant = -stackView.frame.size.width / 4
    }
    
    @IBAction func expensiveBtnClicked(sender: AnyObject) {
        self.selectionviewCenterCon.constant = -stackView.frame.size.width / 4
        UIView.animateWithDuration(0.3) {
            self.selectionView.backgroundColor = UIColor.redColor()
            self.view.layoutIfNeeded()
        }
    }
    
    @IBAction func incomeBtnClicked(sender: AnyObject) {
        self.selectionviewCenterCon.constant = stackView.frame.size.width / 4
        UIView.animateWithDuration(0.3) {
            self.selectionView.backgroundColor = UIColor.greenColor()
            self.view.layoutIfNeeded()
        }
    }
    

    这段代码给出的输出为:

    【讨论】:

    • 我唯一的问题是 selectionView 总是从中间开始。与 Storyboard 中的设置相同。
    • 您在其中一个按钮上添加选择视图,而不是将其添加到视图中。它还需要约束,因为您以编程方式添加选择视图。所以最好在xib中添加选择视图。
    • 我就是这么做的。不再以编程方式创建。选择视图被添加到包含堆栈视图的视图容器中。
    • 可能会缺少对容器/选择/堆栈的约束。因为如果你添加了正确的约束,它不应该发生。将您的约束与我的比较或显示您有问题的约束!
    • 我已经用我的选择视图约束更新了问题
    猜你喜欢
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 2020-12-30
    相关资源
    最近更新 更多