繁体   English   中英

UIView没有从右到左水平设置动画

[英]UIView doesn't animate horizontally from right to left

我在水平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的当前约束:

在此输入图像描述

目标

编程方式创建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但是如果你已经将它添加到另一个按钮中,则必须使用以下行将其从expensiveButton中删除:

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

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

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

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

在此输入图像描述

更新

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

一个代码示例

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)

图片

在此输入图像描述

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

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

如果您这样想的话,这可能更容易可视化:为了从右按钮的坐标空间移动到左按钮的位置,selectionView的中心x将需要是负数,因为它需要是右键前缘左侧。 但是,左侧按钮的中心相对于其自己的超级视图具有正x值。 因此,如果选择视图的中心位于右侧按钮的坐标空间内,则将其设置为左侧按钮的中心将永远不会向左移动。

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

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

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

TLDR;

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

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

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

在此输入图像描述

选择视图具有以下约束:

在此输入图像描述

在4个约束中,第一个约束(将中心X对齐到堆栈视图)是视图控制器。 总奥特莱斯如下:

@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()
    }
}

此代码将输出提供为:

在此输入图像描述

在此输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM