знікаць паміж двума малюнкамі UIButton

я хачу знікаць паміж двума малюнкамі UIButton з мэтай ўстанаўлення абраных у UITableView.

У цяперашні час пераход ажыццяўляецца без эфекту - гэта проста змяняе малюнкі непасрэдна на клік/кантакт:

trans_img = [UIImage imageNamed:@"fav_on.png"];

NSArray *subviews = [owningCell subviews];
UIButton *favbutton = [subviews objectAtIndex:2];

favbutton.imageView.animationImages =
[NSArray arrayWithObjects:trans_img,
 nil];

[favbutton.imageView startAnimating];

Усё, што я знайшоў быў пераход паміж UIViews :(

Было б добра, калі fav_off малюнак становіцца плаўна ператвараецца ў fav_on і наадварот, як FadeIn/Згасанне.

9

7 адказы

Падобна на тое, што вы шукаеце гэта. Ён ажыўляе малюнка на UIButton без дадання новых малюнкаў, ствараючы масіў або змены значэння альфа!

CABasicAnimation *crossFade = [CABasicAnimation animationWithKeyPath:@"contents"];
crossFade.duration = 0.7;
crossFade.fromValue = (id)oldImage.CGImage;
crossFade.toValue = (id)newImage.CGImage;
crossFade.removedOnCompletion = NO;
crossFade.fillMode = kCAFillModeForwards;
[button.imageView.layer addAnimation:crossFade forKey:@"animateContents"];

//Make sure to add Image normally after so when the animation
//is done it is set to the new Image
[button setImage:newImage forState:UIControlStateNormal];
31
дададзена
Дзякуй за міні-ўрок па выкарыстанні Core Animation!
дададзена аўтар phatmann, крыніца
З цікаўнасці, чаму вы вырашылі ўсталяваць removedOnCompletion у NO ?
дададзена аўтар ravron, крыніца
@RileyAvron Што гэта робіць, гэта пераканацца, што анімацыя не атрымлівае вярнуўся ў канцы. Па праўдзе кажучы, я не ўпэўнены, калі гэта 100% для гэтага трэба, таму што мы ўсталёўваем newImage як малюнак гэтай кнопкі ў любым выпадку ... але я звычайна заўсёды дадаць яго там, каб быць бяспечным
дададзена аўтар jkanter, крыніца

Тут у стрыжы:

  import UIKit

   extension UIButton {

       func changeImageAnimated(image: UIImage?) {
           guard let imageView = self.imageView, currentImage = imageView.image, newImage = image else {
               return
           }
           let crossFade: CABasicAnimation = CABasicAnimation(keyPath: "contents")
           crossFade.duration = 0.3
           crossFade.fromValue = currentImage.CGImage
           crossFade.toValue = newImage.CGImage
           crossFade.removedOnCompletion = false
           crossFade.fillMode = kCAFillModeForwards
           imageView.layer.addAnimation(crossFade, forKey: "animateContents")
       }
   }


   self.playAndPauseVideo.changeImageAnimated(UIImage(named: "pauseVideo"))
6
дададзена
выдатна! дзякуй! адна заўвага: я дадаў апошні радок у Func self.setImage (newImage, для: .Normal). Гэта неабходна для другога націску на кнопку
дададзена аўтар Vladimir Vozniak, крыніца

Дзякуй @jkanter за вялікі адказ. Я зрабіў міну ў Swift 3.0 пашырэння, што я думаў, што можа быць карысна для тых, хто наторкаецца на гэтую пасаду.

extension UIButton {

    func setImage(_ image: UIImage?, for state: UIControlState, animated: Bool) {
        guard animated, let oldImage = imageView?.image, let newImage = image else {
           //Revert to default functionality
            setImage(image, for: state)
            return
        }

        let crossFade = CABasicAnimation(keyPath:"contents")
        crossFade.duration = 0.35
        crossFade.fromValue = oldImage.cgImage
        crossFade.toValue = newImage.cgImage
        crossFade.isRemovedOnCompletion = false
        imageView?.layer.add(crossFade, forKey: "animateContents")

        setImage(image, for: state)
    }
}
5
дададзена

Гэта невялікае паляпшэнне адказ @ Ponja, што ў цэлым працуе добра. На жаль, newImage не «перніка», так што калі вы хочаце, каб пераключацца паміж двума малюнкамі, то першае заміранне будзе працаваць гладка, але вярнуцца да зыходнага малюнку будзе «хапаць» таму, не вяне. Фіксаваны яго з дапамогай CATransaction:

import UIKit

extension UIButton {
    func changeImageAnimated(image: UIImage?) {
        guard let imageView = self.imageView, currentImage = imageView.image, newImage = image else {
            return
        }
        CATransaction.begin()
        CATransaction.setCompletionBlock {
            self.setImage(newImage, forState: UIControlState.Normal)
        }
        let crossFade: CABasicAnimation = CABasicAnimation(keyPath: "contents")
        crossFade.duration = 0.3
        crossFade.fromValue = currentImage.CGImage
        crossFade.toValue = newImage.CGImage
        crossFade.removedOnCompletion = false
        crossFade.fillMode = kCAFillModeForwards
        imageView.layer.addAnimation(crossFade, forKey: "animateContents")
        CATransaction.commit()
    }
}
3
дададзена
Я ў канчатковым выніку проста дадаць яшчэ адзін CABasicAnimation асобна для колеру, які, здаецца, каб зрабіць працу.
дададзена аўтар Morgan, крыніца
Гэта працуе вельмі добра, але ў мяне ёсць tintColor і гэта ператварае яго ў чорны колер. Вы ведаеце, як я магу падтрымліваць бягучы tintColor?
дададзена аўтар Morgan, крыніца

Вы маглі б паспрабаваць перайсці альфа-значэнне, як гэта, каб атрымаць эфект, які вы хочаце:

trans_img = [UIImage imageNamed:@"fav_on.png"];

NSArray *subviews = [owningCell subviews];
UIButton *favbutton = [subviews objectAtIndex:2];
[UIView animateWithDuration:0.5 animations:^{
    favbutton.alpha = 0.0f;
} completion:^(BOOL finished) {
    favbutton.imageView.animationImages = [NSArray arrayWithObjects:trans_img,nil];
    [favbutton.imageView startAnimating];
    [UIView animateWithDuration:0.5 animations:^{
        favbutton.alpha = 1.0f;
    }];
}];
2
дададзена
Гэта працуе, але я не разумею, чаму. Не маглі б вы растлумачыць другую частку з animationImages?
дададзена аўтар Fabien Warniez, крыніца
гэта проста дзіўна :)
дададзена аўтар user1069822, крыніца

jkanter answer in Swift:

let crossFade = CABasicAnimation.init(keyPath: "contents")
crossFade.duration = 0.7
crossFade.fromValue = oldImage.cgImage
crossFade.toValue = newImage.cgImage
crossFade.isRemovedOnCompletion = false
crossFade.fillMode = kCAFillModeForwards
button.imageView?.layer.add(crossFade, forKey: "animateContents")

//Make sure to add Image normally after so when the animation
//is done it is set to the new Image
button.setImage(newImage, for: .normal)
1
дададзена
Чаму downvote? Я ў парадку, але, калі ласка, не саромейцеся згадаць прычыну.
дададзена аўтар Hemang, крыніца

@ Адказ SuperDuperTango з tintColor дадаў:

extension UIButton {
    func changeImageAnimated(image: UIImage?) {
        guard let imageView = self.imageView, currentImage = imageView.image, newImage = image else {
            return
        }
        CATransaction.begin()
        CATransaction.setCompletionBlock {
            self.setImage(newImage, forState: UIControlState.Normal)
        }
        let crossFade: CABasicAnimation = CABasicAnimation(keyPath: "contents")
        crossFade.duration = 0.3
        crossFade.fromValue = currentImage.CGImage
        crossFade.toValue = newImage.CGImage
        crossFade.removedOnCompletion = false
        crossFade.fillMode = kCAFillModeForwards
        imageView.layer.addAnimation(crossFade, forKey: "animateContents")
        CATransaction.commit()

        let crossFadeColor: CABasicAnimation = CABasicAnimation(keyPath: "contents")
        crossFadeColor.duration = 0.3
        crossFadeColor.fromValue = UIColor.blackColor()
        crossFadeColor.toValue = UIColor(red: 232.0/255.0, green: 85.0/255.0, blue: 71.0/255.0, alpha: 1.0)
        crossFadeColor.removedOnCompletion = false
        crossFadeColor.fillMode = kCAFillModeForwards
        imageView.layer.addAnimation(crossFadeColor, forKey: "animateContents")
        CATransaction.commit()
    }
}
1
дададзена