过年了,下场红包雨吧
过年了,使用属性动画和自定义view做了个下红包雨的动画,单机版。
效果图:
模拟器鼠标点击效果不是很好,真机上会好很多.
代码,先自定义一个红包View,画出需要的红包图片,当红包被点击时换一张表示拆开红包的图片,其他的都写在注视里.
/**
* Created by weng on 2018/1/27.
*/
public class RedPacketView extends View {
private float amount;//每个红包的金额
private boolean isClicked;//判断红包是否被点击过,点击之后再点不会触发效果
private Bitmap redPacketBitmap;//红包对应的bitmap
private Paint paint;
private int width = 50;
private int height= 50;
public RedPacketView(Context context) {
this(context, null);
}
public RedPacketView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RedPacketView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//设置默认的为拆开的红包图片
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.red_packet);
redPacketBitmap = Bitmap.createScaledBitmap(bitmap, (int) dpToPixel(width), (int) dpToPixel(height), false);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//这里直接设置了大小,如果想更精确一些,也可以设置为屏幕宽度和高度的百分比,这样适配会更好一些
setMeasuredDimension((int) dpToPixel(width), (int) dpToPixel(height));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(redPacketBitmap, 0, 0, paint);
}
//设置红包被拆开的图片
private void setRedPacketBitmap() {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.money);
redPacketBitmap = Bitmap.createScaledBitmap(bitmap, (int)dpToPixel(width), (int)dpToPixel(height), false);
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN :
//获取点击事件,如果未被拆开,点击之后设置拆开的图片
if (!isClicked()) {
setClicked(true);
setRedPacketBitmap();
}
break;
}
return true;
}
public float getAmount() {
return amount;
}
public void setAmount(float amount) {
this.amount = amount;
}
public boolean isClicked() {
return isClicked;
}
public void setClicked(boolean clicked) {
isClicked = clicked;
}
}
接下来是Activity的设置:
public class MainActivity extends AppCompatActivity {
private int[] mSize;//保存屏幕尺寸
private FrameLayout mFrameLayout;
private int mTotalAmount;//保存抢到的红包总金额
private int mTotalAccount = 100;//红包的个数
private int mCurrentAccount;//当前生成的个数,一旦达到总的红包个数,停止继续生成红包
private static final int mInitY = 60;
private int mDuration = 3000;//每个动画的默认时长
private int mDelay = 300;//每次生成红包的默认间隔
private TimeInterpolator[] mInterpolators;//保存不同的插值器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSize = getWindowWidthAndHeight(this);//获取屏幕的宽和高
initInterpolator();//设置好插值器数组,然后随机设置插值器,红包的动画就会速度不同的效果
mFrameLayout = findViewById(R.id.rl_container);
startAnimation();//开始动画
}
//循环生成红包,使用static,不持有Activity的引用
private static Handler mHandler = new Handler();
private void startAnimation() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (mCurrentAccount > mTotalAccount) {
return;
}else {
mCurrentAccount++;
}
final RedPacketView redPacketView = new RedPacketView(MainActivity.this);
redPacketView.setAmount(getRandomFloat(50));//每个红包的额度暂定为50,其实这个应该是后端传过来的数据,这里省略
mFrameLayout.addView(redPacketView);//把红包添加进来
redPacketView.setX(getInitialX());
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(redPacketView, "translationY",
-dpToPixel(mInitY),mSize[1] + dpToPixel(mInitY));
//随机设置插值器
objectAnimator.setInterpolator(mInterpolators[getRandomInt(3)]);
//设置动画时长,也可以设置成随机的
objectAnimator.setDuration(mDuration);
//给动画添加监听器,当动画结束时,主要做两件事1.判断红包是否被拆开,如拆开,增加抢到的红包金额
//2.remove子view
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (redPacketView.isClicked()) {
mTotalAmount += redPacketView.getAmount();
Log.e("MainActivity", "抢到的红包总额 " + mTotalAmount);
}
mFrameLayout.removeView(redPacketView);//一旦动画结束,立即remove,让系统及时回收
}
});
objectAnimator.start();
mHandler.postDelayed(this, mDelay);
}
}, mDelay);
}
//红包生成时的初始X坐标,这里设置为0-屏幕width-红包width
private float getInitialX(){
int max = (int)(mSize[0] - dpToPixel(50));
Random random = new Random();
float ranNum = random.nextInt(max);
return ranNum;
}
private void initInterpolator () {
//这里设置了属性动画的不同的插值器,第一个是线性Interpolator,匀速,第二个持续加速,第三个先加速再减速
//如果对动画还有不了解的,推荐博客:http://hencoder.com/page/2/
mInterpolators = new BaseInterpolator[] {new LinearInterpolator(), new AccelerateInterpolator(),
new AccelerateDecelerateInterpolator()};
}
}
最后是工具类Utils:
/**
* Created by why on 2018/1/29.
*/
public class Utils {
//dp转px
public static float dpToPixel(float dp) {
DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
return dp * displayMetrics.density;
}
//获取屏幕尺寸
public static int[] getWindowWidthAndHeight(Context context) {
WindowManager windowManager = ((Activity)context).getWindowManager();
return new int[] {windowManager.getDefaultDisplay().getWidth(),
windowManager.getDefaultDisplay().getHeight() };
}
public static float getRandomFloat(int max) {
Random random = new Random();
return random.nextInt(max);
}
public static int getRandomInt(int max) {
Random random = new Random();
return random.nextInt(max);
}
}
这样一个简易的单机版红包雨就出来了,代码很少,主要用到的就是动画的一些知识,如果是要做一个多人拼抢的红包雨游戏,还有很多细节优化,包括金额,规则,同步等等。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。