android 数字连击动画,iOS - 礼物连击动画

简单结构分析:

在做礼物点击的时候,我们先把需要显示在屏幕上的礼物放入到一个容器containerView中如下图的红色框,将一个礼物当做成一个通道channelView,当屏幕或者容器显示不了这么多通道的时候,我们将还未执行的通道礼物3放入一个缓存数组中等待执行

441b2e1e9d2f?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

Snip20170811_3.png

441b2e1e9d2f?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

01.gif

一 :DigitLabel基本效果

1.数字的描边效果: 重写override func drawText(in rect: CGRect)方法,先画出一条橙色的外边然后再画一条白色的 这样显示的效果就很描边一样。

class HJGiftDigitLabel: UILabel {

override func drawText(in rect: CGRect) {

// 1.获取当前上下文

let content = UIGraphicsGetCurrentContext()

content?.setLineJoin(.round)

content?.setLineWidth(5.0)

content?.setTextDrawingMode(.stroke)

textColor = UIColor.orange

super.drawText(in: rect)

content?.setTextDrawingMode(.fill)

textColor = UIColor.white

super.drawText(in: rect)

}

2.数字的动画效果:首先使得数字动画放大多倍,然后再缩小,再回到原来的大小。

func ShowDigitAnimation(_ complection: @escaping () -> ()) {

UIView.animateKeyframes(withDuration: 0.25, delay: 0, options: [], animations: {

UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5, animations: {

self.transform = CGAffineTransform(scaleX: 3.0, y: 3.0)

})

UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5, animations: {

self.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)

})

}) { (isFinished) in

UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 10, options: [], animations: {

self.transform = CGAffineTransform.identity

}, completion: { (isFinifshed) in

complection()

})

}

二 :礼物通道ChannelView的设计与实现

1.通过xib描述好View,并使用代码完成基本的UI设置。

// MARK:- 设置UI界面

extension HJGiftChannelView {

override func layoutSubviews() {

super.layoutSubviews()

bgView.layer.cornerRadius = frame.height * 0.5

iconImageView.layer.cornerRadius = frame.height * 0.5

bgView.layer.masksToBounds = true

iconImageView.layer.masksToBounds = true

iconImageView.layer.borderWidth = 1

iconImageView.layer.borderColor = UIColor.green.cgColor

}

}

2.我们的用户名称(userName) 用户头像(userIcon) 礼物名称(GiftName) 礼物图片(GiftURL)基本都是由外部的参数传入进来,所以我们定义一个GiftChannelModel

class HJGiftChannelModel: NSObject {

var senderName : String = ""

var senderUrl : String = ""

var GiftName : String = ""

var GiftUrl : String = ""

init(_ senderName : String,_ senderUrl : String,_ GiftName : String,_ GiftUrl : String) {

self.senderName = senderName

self.senderUrl = senderUrl

self.GiftName = GiftName

self.GiftUrl = GiftUrl

}

// 重写isEqual方法

override func isEqual(_ object: Any?) -> Bool {

guard let object = object as? HJGiftChannelModel else {

return false

}

guard object.senderName == senderName && object.GiftName == GiftName else {

return false

}

return true

}

}

通过定义好的GiftChannelModel给我们的GiftChannelView的UI属性设置好基本的信息

var giftModel : HJGiftChannelModel? {

didSet{

// 1. 模型校验

guard let giftModel = giftModel else {

return

}

// 2. 设置基本信息

iconImageView.image = UIImage(named: giftModel.senderUrl)

senderLabel.text = giftModel.senderName

giftDescLabel.text = "送出礼物:【\(giftModel.GiftName)】"

giftImageView.image = UIImage(named: giftModel.GiftUrl)

4. 执行动画,我们的动画效果是直接从屏幕的直接进入到屏幕上 并且在屏幕上显示三秒之后才开始消失动画,所以在我们需要知道礼物通道(ChannelView)的状态是在animating //正在执行动画 idle //闲置的 willEnd //将要结束动画 endAnimating //已经结束动画所以定义一个枚举 enum HJGiftChannelState

enum HJGiftChannelState {

case idle //闲置的

case animating //正在执行动画

case willEnd //将要结束动画

case endAnimating //已经结束动画

}

动画显示的时候我们需要第一步:当显示在屏幕上的时候则调用DigitLabel的动画,如果动画的状态即将的消失的时候则我们让ChannelView在屏幕上停留3秒再消失

//MARK: -执行动画

extension HJGiftChannelView {

func performAnimation(){

digitLabel.alpha = 1.0

digitLabel.text = " x1 "

UIView.animate(withDuration: 0.25, animations: {

self.alpha = 1.0

self.frame.origin.x = 0

}) { (isFinished) in

self.performDigitAnimation()

}

}

func performDigitAnimation(){

currentNumber += 1

digitLabel.text = " x\(currentNumber) "

digitLabel.ShowDigitAnimation {

if self.currentCacheNumber > 0 {

self.currentCacheNumber -= 1

self.performDigitAnimation()

}else {

self.channelViewState = .willEnd

self.perform(#selector(self.performEndAnimation), with: nil, afterDelay: 3.0)

}

}

}

如果礼物在即将消失self.channelViewState = .willEnd的状态下,用户又点击了赠送礼物,则需要重新启动动画并将之前的停留3秒状态取消

if channelViewState == .willEnd {

performAnimation()

// 取消延迟3秒

NSObject.cancelPreviousPerformRequests(withTarget: self)

如果不是的上述的状态则让其加入我们的缓存中等待执行

extension HJGiftChannelView {

//添加到缓存池

func addOneToCache(){

if channelViewState == .willEnd {

performAnimation()

// 取消延迟3秒

NSObject.cancelPreviousPerformRequests(withTarget: self)

} else {

currentCacheNumber += 1

}

}

三 : 将ChannelView 添加到容器GiftContainerView中

import UIKit

private let kChannelCount = 2

private let kChannelViewH : CGFloat = 40

private let kChannelMargin : CGFloat = 10

class HJGiftContainerView: UIView {

fileprivate lazy var channelViews : [HJGiftChannelView] = [HJGiftChannelView]()

fileprivate lazy var cacheGiftModels : [HJGiftChannelModel] = [HJGiftChannelModel]()

override init(frame: CGRect) {

super.init(frame: frame)

setupUI()

}

required init?(coder aDecoder: NSCoder) {

fatalError("init(coder:) has not been implemented")

}

}

//MARK: -设置UI

extension HJGiftContainerView {

fileprivate func setupUI(){

let w : CGFloat = frame.width

let h : CGFloat = kChannelViewH

let x : CGFloat = 0

for i in 0..

let y : CGFloat = (h + kChannelMargin) * CGFloat(i)

let channelView = HJGiftChannelView.loadFormNib()

channelView.frame = CGRect(x: x, y: y, width:w, height: h)

channelView.alpha = 0

addSubview(channelView)

channelViews.append(channelView)

判断正在忙的ChanelView和新赠送的新礼物的用户名称 和 礼物名称 (username && giftname)是否相同

extension HJGiftContainerView {

func showModel(_ giftModel : HJGiftChannelModel){

// 1.判断正在忙的ChanelView和赠送的新礼物的(username/giftname)

if let channelView = checkUsingChanelView(giftModel) {

channelView.addOneToCache()

return

}

// 2. 判断有没有闲置的channelView

if let channelView = checkIdleChannelView(){

channelView.giftModel = giftModel

return

}

// 3. 将数据加入缓存中

cacheGiftModels.append(giftModel)

}

//检查正在使用的channelView

private func checkUsingChanelView(_ giftModel : HJGiftChannelModel) -> HJGiftChannelView? {

for channelView in channelViews {

if giftModel.isEqual(channelView.giftModel)

&& channelView.channelViewState != .endAnimating {

return channelView

}

}

return nil

}

//检查有没有闲置的channel

private func checkIdleChannelView() -> HJGiftChannelView? {

for channelView in channelViews {

if channelView.channelViewState == .idle {

return channelView

}

}

return nil

}

}

监听ChannelView什么时候完成动画,判断缓存中是否有内容,通过reversed()反序遍历的方式来确定我们的firstModel相同的模型放入到ChanelView缓存中继续执行动画

channelView.complectionCallback = { channelView in

// 1.取出缓存中的模型

guard self.cacheGiftModels.count != 0 else {

return

}

// 2.取出缓存中的第一个模型数据

let firstModel = self.cacheGiftModels.first!

self.cacheGiftModels.removeFirst()

// 3.让闲置的channelView执行动画

channelView.giftModel = firstModel

// 4.将数组中剩余有和firstModel相同的模型放入到ChanelView缓存中

for i in (0..

let giftModel = self.cacheGiftModels[i]

if giftModel .isEqual(firstModel) {

channelView.addOneToCache()

self.cacheGiftModels.remove(at: i)

}

}

}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android仿iOS桌面应用删除动画可以使用属性动画实现。以下是一个简单的实现步骤: 1. 创建一个布局文件,用于显示要删除的应用图标。在这个布局中,你可以使用ImageView来显示应用图标,然后添加一个TextView来显示删除提示。 2. 在Java代码中,使用属性动画设置ImageView的透明度和缩放比例。通过逐渐降低透明度和缩放比例,可以创建一个逐渐消失的效果。 3. 在动画结束时,删除应用程序,并在屏幕上显示一个Snackbar或Toast,以显示已删除的应用程序名称。 下面是一个示例代码,可以让你更好地了解如何实现这个功能: ```java public class DeleteAnimationActivity extends AppCompatActivity { private ImageView mAppIcon; private TextView mDeleteHint; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_delete_animation); mAppIcon = findViewById(R.id.iv_app_icon); mDeleteHint = findViewById(R.id.tv_delete_hint); // 设置属性动画 ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(mAppIcon, "alpha", 1f, 0f); ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(mAppIcon, "scaleX", 1f, 0f); ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(mAppIcon, "scaleY", 1f, 0f); // 设置动画集合 AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(alphaAnimator, scaleXAnimator, scaleYAnimator); animatorSet.setDuration(500); // 监听动画结束事件 animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // 删除应用程序 deleteApp(); // 显示Snackbar或Toast Snackbar.make(mAppIcon, "已删除应用程序", Snackbar.LENGTH_LONG).show(); } }); // 启动动画 animatorSet.start(); } private void deleteApp() { // 删除应用程序的代码 } } ``` 在上面的代码中,我们使用 ObjectAnimator 来设置透明度和缩放比例的动画,然后使用 AnimatorSet 将它们组合在一起。在动画结束时,我们删除应用程序并显示一个Snackbar或Toast。 如果你想要更加复杂的删除动画效果,可以尝试使用 PathInterpolator 或自定义 Interpolator 来控制动画的速度和加速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值