簡體   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