自定义view 落叶效果

实现树叶飘落的一个自定义view  实际项目中几乎没有这个需求,但是做出来可以学习进步,有兴趣的童鞋可以看看。

先看图吧:

(可能需要少许时间加载,稍等..)


就是这么一个效果。


主要涉及到canvas、paint、bitmap和matrix的使用,这几个类也是自定义view的时候高频率用到的工具。所以熟练掌握这几个类的使用对自定义控件功力的提升是有很大帮助的。


我们从头来理一下实现的过程。

首先,画一片叶子:(叶子资源:

主要方法就一个:canvas.drawBitmap(leafBitmap, matrix, bitmapPaint);

三个参数:

leafBitmap 通过资源图片获取bitmap (BitmapFactory.decodeResource(context.getResources(), R.drawable.leaf) )

matrix负责位置和角度的变化

bitmapPaint 为画笔Paint的一个实例化对象

搞清楚这个方法过后,调用一下,一片叶子就绘到屏幕上了。

画一片叶子很简单!


然后,当要画很多叶子时,由于每片叶子的位置和角度是不断变化的,我们创建一个类来记录每片叶子自身的位置角度信息。

<span style="font-size:14px;">private class leafPosition {
		public int x = 0;		//位置x坐标信息
		public int y = 0;		//位置y坐标信息
		public int roate = 0;		//角度信息
		public int roateChange = 0; 		//角度变化值

		public leafPosition(int x, int y, int roate) {
			this.x = x;
			this.y = y;
			this.roate = roate;
		}
	}</span>
然后,要同时画很多片叶子,我们需要一个数据容器,这里就用ArrayList来承担这个角色吧。所以new一个。

<span style="font-size:14px;">List leafs = ArrayList<LeafFallingView.leafPosition>();</span>

然后是树叶的产生和变化:

树叶产生时,我们通过当前世界时间和随机数为参照来随机确定它在屏幕的位置和角度,这样,每一片树叶产生的时候就随机的在屏幕不同的位置出现了。

float r = random.nextFloat();
// 根据当前时间随机创建 位置、旋转角度不同的叶子
leafs.add(new leafPosition((int) (((r * 1000 % 100f) / 100f) * viewWidth), 0, (int) nowTime % 360));


树叶的变化,其实就是不断的改变叶子的位置与角度信息,不断重绘整个view来实现的,就像放电影一样,改变一点,重绘一帧图像,再改变一点,再重绘一帧图像,不断进行,以实现动画效果。我们用一个setParam方法以一定的规律改变每片叶子的信息(每次移动一个微小的位移,旋转一个微小的角度),再重绘view。然后延时一定时间递归调用自己,达到不停的修改叶信息,不停重绘的目的。这样就实现了动态的满屏飘落叶的效果。

这个过程中有一个重要的角色就是matrix,这里主要是平移和旋转的效果,对应两个方法的使用:

matrix.postTranslate(x, y); 

matrix.postRotate(roate % 360, nowX + leafWidth / 2, nowY + leafHeight / 2); 

关于matrix矩阵的详细原理和介绍可以去度娘或者google一下,按矩阵来乘之类的,很详细,也很晕(线性代数早还给大学老师了哭)。

这里用到的两个方法,一个平移,一个旋转。postTranslate的参数即是x和y方向的平移距离,postRotate的参数分别是旋转角度,和旋转中心的x、y坐标。这里取叶子的中心为旋转中心。


然后就执行主要流程,先逐渐添加树叶,然后不停地设置所有树叶的位置信息,不停地重绘view就实现了最终的效果了。

最后,可以给自己配一个喜欢的背景颜色或者图片,就大功告成。


贴上代码:

package com.cc.test.view;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.cc.test.R;

/**
 * 自定义落叶view
 * @author zhangyu
 * @date 2016-4-1
 * @描述:
 */
public class LeafFallingView extends View {

	private static final String TAG = "LeafFallingView";
	private Context context;
	private Bitmap leafBitmap;
	private Paint bitmapPaint, orangePaint;
	private int viewWidth, viewHeight, leafWidth, leafHeight;
	private Handler handler;
	private List<leafPosition> leafs;
	private Random random = new Random(333);

	public LeafFallingView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init(context);
	}

	public LeafFallingView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public LeafFallingView(Context context) {
		super(context);
		init(context);
	}

	private void init(Context context) {
		this.context = context;
		leafBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.leaf);
		leafWidth = leafBitmap.getWidth();
		leafHeight = leafBitmap.getHeight();
		initPaint();
		handler = new Handler();

		leafs = new ArrayList<LeafFallingView.leafPosition>();

		setParams();
	}

	private void initPaint() {
		bitmapPaint = new Paint();
		bitmapPaint.setAntiAlias(true);
		bitmapPaint.setDither(true);
		bitmapPaint.setFilterBitmap(true);

		orangePaint = new Paint();
		orangePaint.setAntiAlias(true);
		orangePaint.setColor(Color.parseColor("#FCE59D"));
	}

	@Override
	protected void onDraw(Canvas canvas) {
		drawOrangeBackground(canvas);
		drawLeaf(canvas);

		super.onDraw(canvas);
	}

	/**
	 * 画叶子
	 * 
	 * @param canvas
	 */
	private void drawLeaf(Canvas canvas) {

		for (int i = 0; i < leafs.size(); i++) {
			leafPosition leaf = leafs.get(i);
			int x = leaf.x;
			int y = leaf.y;
			int roate = leaf.roate;

			int nowX = 0, nowY = 0;
			canvas.save();
			Matrix matrix = new Matrix();
			matrix.postTranslate(x, y);
			nowX = nowX + x;
			nowY = nowY + y;
			matrix.postRotate(roate % 360, nowX + leafWidth / 2, nowY + leafHeight / 2);

			canvas.drawBitmap(leafBitmap, matrix, bitmapPaint);
			canvas.restore();
		}
	}

	/**
	 * 画背景
	 * 
	 * @param canvas
	 */
	private void drawOrangeBackground(Canvas canvas) {
		canvas.drawRect(0, 0, viewWidth, viewHeight, orangePaint);
	}

	private int setCount = 0;		//记录设置次数

	/**
	 * 设置和改变叶子位置和角度参数
	 */
	public void setParams() {
		Log.d(TAG, "setParams.. setCount = " + setCount);
		setCount++;

		handler.postDelayed(new Runnable() {
			public void run() {

				long nowTime = System.currentTimeMillis();
				nowTime = (nowTime + setCount) / 3;

				if (setCount % 7 == 0) {

					float r = random.nextFloat();
					Log.d(TAG, "r = " + r + ",((r % 100f) / 100f) = " + ((r % 100f) / 100f));
					// 根据当前时间随机创建 位置、旋转角度不同的叶子
					leafs.add(new leafPosition((int) (((r * 1000 % 100f) / 100f) * viewWidth), 0, (int) nowTime % 360));
				}

				if (leafs.size() > 300)
					leafs.remove(0);
				Log.d(TAG, "leafs.size = "+ leafs.size());

				for (int i = 0; i < leafs.size(); i++) {
					leafPosition leaf = leafs.get(i);

					leaf.y += 3;//y方向每次移动3个像素
					//根据叶子在集合中的排序位置来产生一个旋转角度(大小方向不完全相同),并且记录下这个角度下次继续执行,保证叶子转向一致,不来回摆动
					if(leaf.roateChange == 0)
						leaf.roateChange = getRoate(i);
					leaf.roate += leaf.roateChange;
				}
				invalidate();
				if (setCount <= 10000) {// 设置10000次,当然也可以不设置次数无限递归下去
					setParams();
				} else
					setCount = 0;
			}
		}, 20);

	}

	/**
	 * 返回几种旋转的值
	 * @param nowTime
	 * @return
	 */
	protected int getRoate(long nowTime) {
		switch ((int) (nowTime % 5)) {
		case 0:
			return 3;
		case 1:
			return -3;
		case 2:
			return 4;
		case 3:
			return -5;
		case 4:
			return -4;
		default:
			return 3;
		}
	}

	@Override
	public void onWindowFocusChanged(boolean hasWindowFocus) {
		viewWidth = getWidth();
		viewHeight = getHeight();
		invalidate();
		super.onWindowFocusChanged(hasWindowFocus);
	}

	/**
	 * 叶子位置
	 * 
	 * @author zhangyu
	 * @date 2016-3-28
	 * @描述:
	 */
	private class leafPosition {
		public int x = 0;		//位置x坐标信息
		public int y = 0;		//位置y坐标信息
		public int roate = 0;		//角度信息
		public int roateChange = 0; 		//角度变化值

		public leafPosition(int x, int y, int roate) {
			this.x = x;
			this.y = y;
			this.roate = roate;
		}
	}
}

 

代码不多,也不算太复杂,希望对需要的童鞋有用,有问题还请大家多多指正!


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值