简体   繁体   中英

Reason why UIView doesn't animate

I am doing this on iOS in Swift. I am trying to animate a UIView just simply updating its frame. I created a custom subclass of UITextField. The code I have is as follows.

import Foundation
import UIKit

enum TextFieldState {
   case Active
   case InactiveBlank
   case InactiveText
}
/**
   Use this class to create any text field in the New workout VC
 */
class TextField: UITextField {
   // MARK: Properties
   /// The color for all accent elements
   private let standardColor: UIColor = Color().blue
   /// The color for all error elements
   private let errorColor: UIColor = Color().red
   /// The font for inactive state
   private let inactiveFont: UIFont = Fonts.Regular().sixteen
   /// The font for active state
   private let activeFont: UIFont = Fonts.Bold().thirtySix
   /// The font for hint active state
   private let activeHintFont: UIFont = Fonts.Regular().sixteen
   /// The font for hint in inactive state
   private let inactiveHintFont: UIFont = Fonts.Regular().twelve
   /// The placeholder and hint for the text field
   let placeholderText: String 
   /// The type of the field
   let type: TextFieldType
   /// The bottom line for the text field
   var bottomLine: UIView { return self.createBottomLine() }
   /// The placeholder for the field
   var placeholderLabel: UILabel { return self.createPlaceholderLabel()     }
   /// The rect for editing and text bounds
   private var textBounds: Rect {
      return Rect(x: 0, y: 31, w: self.frame.w, h: 96)
   }
   /// The variable for the text of the text field


  // MARK: Initializers
 /// Default initalizer
 init<A: TextFieldOptions>(frame: CGRect, options: A) {
    // Set the placeholder text value
    self.placeholderText = options.placeHolderText
    // Set the type of the text field
    self.type = options.type
    // Call the super initalizer
    super.init(frame: frame)
    // Update settings based on type
    self.styleType()
    // Set the delgate for the text field
    self.delegate = self
    // Set the background color
    self.backgroundColor = Color().white
    // Set the font for the text field
    self.font = self.activeFont
    // Layout all the views
    self.layoutViews()

 }

  /// Required by Apple NEVER USE
  required init?(coder aDecoder: NSCoder) {
      fatalError("This class doesn't support NSCoding")
   }



// MARK: Functions
private func layoutViews() {

  // Add the placeholder text to the text field
  self.addSubview(self.placeholderLabel)
  // Add the bottom line to the text field
  self.addSubview(self.bottomLine)

}

private func styleType() {
   if self.type == .All {
      self.returnKeyType = .Next
      self.autocorrectionType = .No
   }
}

private func createBottomLine() -> UIView {

   // Get the y position for the line
   let y: CGFloat = self.placeholderLabel.frame.origin.y + self.placeholderLabel.frame.height + 4
   // Create the frame for the bottom line
   let bottomLineFrame: Rect = Rect(x: 0, y: y , w: self.frame.w, h: 1)
   // Create the bottom line
   let botttomLine: Line = Line(frame: bottomLineFrame, alpha: 0.38)
   // Return the bottom line
   return botttomLine

}

private func createPlaceholderLabel() -> UILabel {

  // Create the frame for the placeholder text
  let placeholderFrame: CGRect = CGRect(x: 0, y: 20, width: self.frame.width, height: 19)
  // Create the placeholder text
  let placeHolder: UILabel = UILabel(frame: placeholderFrame, font: self.inactiveFont, align: .Left, color: Color().black)
  // Set the alpha for the placeholder
  placeHolder.alpha = 0.38
  // Set the text for the placeholder
  placeHolder.text = self.placeholderText
  // Return the placeholder
  return placeHolder


}

/**
  This function updates the style for the text field
  - parameter state: The state that the text field is current
*/
private func updateStyle(state: TextFieldState) {

  switch state {
  case .Active:
     self.activeStyle()
  case .InactiveBlank:
     print("Update inactive blank for state & style changes")
  case .InactiveText:
     print("Update inactive text for state and style changes")
  }

}

/**
  This function is for when a text field is in an active state and needs to be style accordingly
*/
private func activeStyle() {

  // Create the animation
  let animate: () -> () = {
     print("ANIMATE!!!")
     self.placeholderLabel.font = self.activeHintFont
     self.placeholderLabel.frame.origin.y = 4
     self.placeholderLabel.textColor = self.standardColor
     self.bottomLine.backgroundColor = self.standardColor
     var newFrame: CGRect = self.bottomLine.frame
     newFrame.origin.y = 86
     self.bottomLine.frame = newFrame
  }
  // Animate the view
  UIView.animateWithDuration(0.3, animations: animate)
  UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveEaseInOut, animations: {
     self.bottomLine.frame.origin.y = 86
     }, completion: nil)
}

   }

// MARK: Methods for text placement
extension TextField {

   override func editingRectForBounds(bounds: CGRect) -> CGRect {
      return textBounds
   }

   override func textRectForBounds(bounds: CGRect) -> CGRect {
      return textBounds
   }


}

// MARK: All delegate methods
extension TextField : UITextFieldDelegate {

   /**
    This function handles when the text field begins editing
   */
   func textFieldDidBeginEditing(textField: UITextField) {
      print("I started editing")
      self.updateStyle(.Active)

   }

   /**
     This function handles when the text field finishes editing
   */
   func textFieldDidEndEditing(textField: UITextField) {
      print("I finished editing")
   }

   /**
      This function handles when the text field changes
   */
   func textFieldDidChange(textField: TextField) {
      print("I changed")
      print("Text = \(self.text)")
   }

}

The animation block gets called but nothing updates. The view is already on screen and I know viewWillApear has already been called. What could cause this type of issue? I have already tried passing the animation onto another thread and that didn't work.

It's the logic for setting frame's y position. The frame can only be set with the view's frame setter.

let newFrame: CGRect = self.bottomLine.frame;
newFrame.origin.y = 86;
self.bottomLine.frame = newFrame;

edit the bottomLine initializer is getting called anew before the animation. A lazy build of that view (by assigning a tag) is a good approach.

Try this:

self.bottomLine.frame = CGRect(x: self.bottomLine.frame.origin.x,
y: 86,
width: self.bottomLine.frame.size.width,
height: self.bottomLine.frame.size.height)

This is how animate your view position, try the following

self.bottomLine.frame.origin.y = 86
UIView.animateWithDuration(0.3, delay: 0.0, options: .CurveEaseInOut, animations: {
     self.layoutIfNeeded()
 }, completion: nil)

it's working try this with delay time

UIView.animateWithDuration(0.4, delay: 2.0, options: .CurveEaseInOut, animations: {
     self.bottomLine.frame.origin.y = 86
}, completion: nil)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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