2016-06-28 32 views
7

Tôi tương đối mới với hoạt ảnh ios và tôi tin rằng có điều gì đó sai với cách tiếp cận mà tôi đã thực hiện để tạo hoạt ảnh cho UIView.Swift - Hoạt ảnh tô màu đầy màu sắc

Tôi sẽ bắt đầu với một ảnh chụp màn hình giao diện người dùng để hình dung ra vấn đề của tôi chính xác hơn:

Có một tế bào tableView với hai nhãn và vòng tròn đầy màu sắc enter image description here

Bất cứ lúc nào tôi giới thiệu giá trị mới cho các tế bào, tôi Tôi muốn tạo hiệu ứng cho bóng đèn trái này nhất nên có vẻ như nó có màu đỏ.

này là việc thực hiện od BadgeView, mà về cơ bản là tận cùng bên trái nói trên điền tròn

class BadgeView: UIView { 

var coeff:CGFloat = 0.5 

override func drawRect(rect: CGRect) { 
    let topRect:CGRect = CGRectMake(0, 0, rect.size.width, rect.size.height*(1.0 - self.coeff)) 
    UIColor(red: 249.0/255.0, green: 163.0/255.0, blue: 123.0/255.0, alpha: 1.0).setFill() 
    UIRectFill(topRect) 

    let bottomRect:CGRect = CGRectMake(0, rect.size.height*(1-coeff), rect.size.width, rect.size.height*coeff) 
    UIColor(red: 252.0/255.0, green: 95.0/255.0, blue: 95.0/255.0, alpha: 1.0).setFill() 
    UIRectFill(bottomRect) 
      self.layer.cornerRadius = self.frame.height/2.0 
    self.layer.masksToBounds = true 
    } 
} 

Đây là cách tôi đạt được lấp đầy không đồng đều - Tôi giới thiệu hệ số mà tôi sửa đổi trong viewController.

Bên trong phương pháp cellForRowAtIndexPath của tôi, tôi cố gắng để animate hình này sử dụng nút tùy chỉnh với callback

let btn:MGSwipeButton = MGSwipeButton(title: "", icon: img, backgroundColor: nil, insets: ins, callback: { 
     (sender: MGSwipeTableCell!) -> Bool in 
     print("Convenience callback for swipe buttons!") 
     UIView.animateWithDuration(4.0, animations:{() -> Void in 
      cell.pageBadgeView.coeff = 1.0 
      let frame:CGRect = cell.pageBadgeView.frame 
      cell.pageBadgeView.drawRect(frame) 
     }) 
     return true 
     }) 

Nhưng nó không làm gì nhưng bản in để an ủi

: CGContextSetFillColorWithColor: 0x0 bối cảnh hợp lệ. Nếu bạn muốn xem backtrace, vui lòng đặt biến môi trường CG_CONTEXT_SHOW_BACKTRACE.

Mặc dù tôi rất muốn biết câu trả lời đúng và cách tiếp cận, nó sẽ là điều tuyệt vời để biết, vì mục đích giáo dục, tại sao mã này không hoạt động. Cảm ơn trước

Trả lời

8

Phần lỗi của vấn đề có vẻ là một phần của mã:

cell.pageBadgeView.drawRect(frame) 

Từ Apple docs trên UIView drawRect:

Phương pháp này được gọi khi chế độ xem được hiển thị lần đầu hoặc khi có t xảy ra làm mất hiệu lực phần hiển thị của chế độ xem. Bạn không bao giờ nên tự gọi phương thức này trực tiếp. Để làm mất hiệu lực một phần của khung nhìn của bạn, và do đó làm cho phần đó được vẽ lại, thay vào đó hãy gọi phương thức setNeedsDisplay hoặc setNeedsDisplayInRect:.

Vì vậy, nếu bạn muốn thay đổi mã của bạn để:

cell.pageBadgeView.setNeedsDisplay() 

Bạn sẽ thoát khỏi các lỗi và xem badgeView điền một cách chính xác. Tuy nhiên, điều này sẽ không hoạt ảnh, vì drawRect không thể hoạt ảnh theo mặc định.

Cách giải quyết dễ nhất đối với vấn đề của bạn sẽ là để BadgeView có chế độ xem nội bộ cho màu tô.Tôi muốn Refactor BadgeView như vậy:

class BadgeView: UIView { 

    private let fillView = UIView(frame: CGRectZero) 

    private var coeff:CGFloat = 0.5 { 
     didSet { 
      // Make sure the fillView frame is updated everytime the coeff changes 
      updateFillViewFrame() 
     } 
    } 

    // Only needed if view isn't created in xib or storyboard 
    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
    } 

    // Only needed if view isn't created in xib or storyboard 
    override init(frame: CGRect) { 
     super.init(frame: frame) 

     setupView() 
    } 

    override func awakeFromNib() { 
     setupView() 
    } 

    private func setupView() { 
     // Setup the layer 
     layer.cornerRadius = bounds.height/2.0 
     layer.masksToBounds = true 

     // Setup the unfilled backgroundColor 
     backgroundColor = UIColor(red: 249.0/255.0, green: 163.0/255.0, blue: 123.0/255.0, alpha: 1.0) 

     // Setup filledView backgroundColor and add it as a subview 
     fillView.backgroundColor = UIColor(red: 252.0/255.0, green: 95.0/255.0, blue: 95.0/255.0, alpha: 1.0) 
     addSubview(fillView) 

     // Update fillView frame in case coeff already has a value 
     updateFillViewFrame() 
    } 

    private func updateFillViewFrame() { 
     fillView.frame = CGRectMake(0, bounds.height*(1-coeff), bounds.width, bounds.height*coeff) 
    } 

    // Setter function to set the coeff animated. If setting it not animated isn't necessary at all, consider removing this func and animate updateFillViewFrame() in coeff didSet 
    func setCoeff(coeff: CGFloat, animated: Bool) { 
     if animated { 
      UIView.animateWithDuration(4.0, animations:{() -> Void in 
       self.coeff = coeff 
      }) 
     } else { 
      self.coeff = coeff 
     } 
    } 

} 

Trong nút gọi lại, bạn sẽ chỉ phải làm:

cell.pageBadgeView.setCoeff(1.0, animated: true) 
+0

Điều này thật tuyệt vời, nhưng nó hoạt động như thế nào? Tại sao lần này animateWithDuration thực hiện công việc của mình? Tại sao tôi không thể đặt animateWithDuration vào gọi lại của mình? Tuy nhiên tôi hoàn toàn yêu thích giải pháp này! – DCDC

+1

@DCDC Bạn có thể đặt animateWithDuration vào cuộc gọi lại của mình. Tuy nhiên tôi đã chọn để có trong BadgeView để bất cứ lúc nào bạn sẽ thiết lập một hệ số mới các hình ảnh động là phù hợp về thời gian hoặc tùy chọn. Ngoài ra, bạn có thể kiểm tra [Xem Hướng dẫn lập trình cho iOS] (https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/AnimatingViews/AnimatingViews.html#//apple_ref/doc/uid/ TP40009503-CH6-SW1) để có cái nhìn chi tiết hơn về cách hoạt ảnh hoạt động và những gì có thể được làm động trong một khối. –

+0

Vâng tôi biết bây giờ. Tôi phải thừa nhận tôi là loại ngạc nhiên như thế nào đơn giản đó. Về cơ bản, tất cả những gì bạn cần làm là chỉ làm thay đổi giá trị của biến coeff và sau đó chỉ cần gọi phương thức có liên quan để vẽ chế độ xem. Big lên người đàn ông cho đến với một giải pháp thực sự đơn giản và mạnh mẽ! – DCDC

3

thử mã này sân chơi

import UIKit 
import CoreGraphics 

var str = "Hello, playground" 

class BadgeView: UIView { 

    var coeff:CGFloat = 0.5 

    func drawCircleInView(){ 
    // Set up the shape of the circle 
     let size:CGSize = self.bounds.size; 
     let layer = CALayer(); 
     layer.frame = self.bounds; 
     layer.backgroundColor = UIColor.blue().cgColor 



     let initialRect:CGRect = CGRect.init(x: 0, y: size.height, width: size.width, height: 0) 

     let finalRect:CGRect = CGRect.init(x: 0, y: size.height/2, width: size.width, height: size.height/2) 

     let sublayer = CALayer() 
     sublayer.frame = initialRect 
     sublayer.backgroundColor = UIColor.orange().cgColor 
     sublayer.opacity = 0.5 


     let mask:CAShapeLayer = CAShapeLayer() 
     mask.frame = self.bounds 
     mask.path = UIBezierPath(ovalIn: self.bounds).cgPath 
     mask.fillColor = UIColor.black().cgColor 
     mask.strokeColor = UIColor.yellow().cgColor 

     layer.addSublayer(sublayer) 
     layer.mask = mask 

     self.layer.addSublayer(layer) 

     let boundsAnim:CABasicAnimation = CABasicAnimation(keyPath: "bounds") 
     boundsAnim.toValue = NSValue.init(cgRect:finalRect) 

     let anim = CAAnimationGroup() 
     anim.animations = [boundsAnim] 
     anim.isRemovedOnCompletion = false 
     anim.duration = 3 
     anim.fillMode = kCAFillModeForwards 
     sublayer.add(anim, forKey: nil) 
    } 
} 

var badgeView:BadgeView = BadgeView(frame:CGRect.init(x: 50, y: 50, width: 50, height: 50)) 
var window:UIWindow = UIWindow(frame: CGRect.init(x: 0, y: 0, width: 200, height: 200)) 
window.backgroundColor = UIColor.red() 
badgeView.backgroundColor = UIColor.green() 
window.becomeKey() 
window.makeKeyAndVisible() 
window.addSubview(badgeView) 
badgeView.drawCircleInView() 
+1

Bạn có thể thấy điều này ở sân chơi như thế nào? Nó không hiển thị bất cứ điều gì trực quan? – user1007522

+1

@ user1007522 Thêm mã này: 'code' nhập khẩu PlaygroundSupport ... ' code' PlaygroundPage.current.needsIndefiniteExecution = true 'code' PlaygroundPage.current.liveView = cửa sổ Sau đó nhấp vào nút xem trước. – mcfroob

0

More Modification mã trên, mã điểm neo đã mất tích trong mã trên

``` 
    var str = "Hello, playground" 

class BadgeView: UIView { 

var coeff:CGFloat = 0.7 

func drawCircleInView(){ 
    // Set up the shape of the circle 
    let size:CGSize = self.bounds.size; 

    let layerBackGround = CALayer(); 
    layerBackGround.frame = self.bounds; 
    layerBackGround.backgroundColor = UIColor.blue.cgColor 
    self.layer.addSublayer(layerBackGround) 


    let initialRect:CGRect = CGRect.init(x: 0, y: size.height , width: size.width, height: 0) 

    let finalRect:CGRect = CGRect.init(x: 0, y: 0, width: size.width, height: size.height) 

    let sublayer = CALayer() 
    //sublayer.bounds = initialRect 
    sublayer.frame = initialRect 
    sublayer.anchorPoint = CGPoint(x: 0.5, y: 1) 
    sublayer.backgroundColor = UIColor.orange.cgColor 
    sublayer.opacity = 1 


    let mask:CAShapeLayer = CAShapeLayer() 
    mask.frame = self.bounds 
    mask.path = UIBezierPath(ovalIn: self.bounds).cgPath 
    mask.fillColor = UIColor.black.cgColor 
    mask.strokeColor = UIColor.yellow.cgColor 

    layerBackGround.addSublayer(sublayer) 
    layerBackGround.mask = mask 

    self.layer.addSublayer(layerBackGround) 

    let boundsAnim:CABasicAnimation = CABasicAnimation(keyPath: "bounds") 
    boundsAnim.toValue = NSValue.init(cgRect:finalRect) 

    let anim = CAAnimationGroup() 
    anim.animations = [boundsAnim] 
    anim.isRemovedOnCompletion = false 
    anim.duration = 1 
    anim.fillMode = kCAFillModeForwards 
    sublayer.add(anim, forKey: nil) 
} 
Các vấn đề liên quan