Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIView doesn't animate horizontally from right to left

Tags:

ios

swift

I have two UIButtons inside an horizontal UIStackView. I want to add a UIView as a subview so that when I press one of the buttons, the view moves horizontally to the selected button.

I have this code:

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
    }

This code actually works when the view is added to the left button. The view will move from left to right and right to left when clicking the buttons.

But if I start with the right button selected:

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

The view only changes the color, but doesn't move from right to left.

Why is that ? How can I fix my code so that the view can be moved either way ?

UPDATE:

I tried adding the stack view inside an UIView and also add the selectionView inside it. Here is a snapshot:

enter image description here

I still have a problem when I run the app with the right button selected, the selectionView appears outside of the containerView (it should appear on the right side of the Expensive text):

enter image description here

This is the code inside viewDidLoad when I check which button should be selected:

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

UPDATE 2:

Current constraints for selectionView:

enter image description here

like image 853
Adrian Avatar asked Oct 29 '22 23:10

Adrian


1 Answers

Objective:

Create programmatically a selectionView to switch throught two UIButton as a child.

To explain better the situation I've added (to start) the selectionView to expensiveButton (the button where you have the issue..)

There are some corrections you could be do in your project to see it working well.

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

Some explaination:

First of all in your project you don't report a global reference to selectView but I think you simply forgot to write it in your question.

So, a good thing is to set a tag to your selectionView, like an id number to can identify it between subviews of his future parent view (in your case it will be a UIButton)

As you can see I've added the viewDidAppear method, why? Because when you are in viewDidLoad your button are not completly ready, so you have a wrong center, the right place to have this value is viewDidAppear when your view is finally painted.

Now let's speaking about selectionView: it's a view, so you can add it to incomeButton but if you already have added it in the other button you must remove it from expensiveButton simply with this line:

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

Finally the center point: remember you are in autolayout so a good way to find it could be by using bounds:

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

This is my project structure , I see you working on it:

enter image description here

Update:

After I've seen your updates (you started with a selectionView created programmatically) some comments and answer about your issue, I've a suspicious you want to realize a custom UISegmentedControl. I think using UIStackView to realize a little control like it it's not a good idea, you can find many project around UISegmentedControl that subclass UIControl like for example BetterSegmentedControl:

A code example:

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)

A picture:

enter image description here

like image 99
Alessandro Ornano Avatar answered Nov 15 '22 06:11

Alessandro Ornano