自定义View之大风车系列demo(一)

每次写博客最讨厌写博客的开头,不知道该写些什么,现在也是,感觉跟写八百字作文似的。之所以会写这一系列的demo是因为前天看网上的一个图片转圈的源码的时候

突发奇想要不要自己也弄个耍耍,顺便学习下view的相关知识!说干就干,当然自己写的时候也不免参照写别人得到代码,毕竟自定义view与我的水平来说确实具有挑战性,通过完成这一些列的小demo确实收获颇多,虽然还有些许在我看来更牛逼的功能自己没法实现,但自己的目的也算达到了。先啰嗦了这么多,先说说大风车系列小demo的总体概况:一共五个版本,这也意味着此系列一共会写四到五个简短的小博客,每个版本都是对上一个版本的修改或者功能的改进。特注:这是个代码很少的demo,不过对于初学者来说确实能学到点东西,所以拿来分享,如果有大神看到这些没什么水平的博客希望能留下自己对android相关知识的些许评价或者批评。总之欢迎批评指正吧,闲言少叙,进入主题:

大风车版本1.0)实现功能和思虑如下:

1)风车图片随着手指的转动而转动,转动的速度固定

2)图片的转动肯定设计到了androidview的重绘过程,所以postInvalidate和invalidate两个方法准备起来。

3)既然图片随着手指的移动而转动,那么肯定会在onTouchEvent对MotionEvent.action_move事件进行补货然后处理

4)所需要的风车图片素材如下:

5)风车的图片宽和高一样,是个正方形的图片,需要计算出来该方正行的中心,以此中心为旋转轴进行旋转。

通过上面五个说明得出自定义的View代码如下:

package rotation.demo.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
 * verson 1.0
 * 随手指转动而转动的风车
 * 转动的思路
 * 1)风车转动的涉及到了图片的重绘过程
 * 2)监听手指的move事件,当move事件被监听到的时候调用相关方法来进行重绘
 * 3)用矩阵变换来实现风车的转动
 * @author xiaobenxiong
 *
 */
public class RotationView extends View{

	/**要转动的图片**/
	private Bitmap bitMap;
	/**风车每次转动的弧度**/
	private  int rad = 30;
	/**图片的宽度:在这里提供的是正方形的图片,所以宽度和高度是一样的**/
	private int width = 0;
	/***图片的高度:在这里提供的是正方形的图片,所以宽度和高度是一样的**/
	private int height = 0;
	/**定义一个画笔**/
	private Paint paint = new Paint();
	public RotationView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

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

	public RotationView(Context context) {
		super(context);
	}

	/**
	 * 获取图片的宽和高
	 */
	public void initSize() {
	  width = bitMap.getWidth();
	  height = bitMap.getHeight();
	  postInvalidate();
	}

	public void setBitMap(Bitmap bitMap) {
		this.bitMap = bitMap;
	}

        //一图片的宽和高来设定自定义View的宽和高,由于是正方形宽和高是一样的
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		setMeasuredDimension(width, width);
	}

          /***
           *实现onDraw方法把风车图片绘制出来,同时绘制出来风车的旋转效果,通过Matrix来控制
          */
         @Override
	    protected void onDraw(Canvas canvas) {

	        Matrix matrix = new Matrix();
	        // 设置转轴位置
	        matrix.setTranslate((float)width / 2, (float)height / 2);
	        rad -=3;//每次旋转的弧度增量为3当然,数字越大转动越快
	        // 开始转
	        matrix.preRotate(rad);
	        // 转轴还原
	        matrix.preTranslate(-(float)width / 2, -(float)height / 2);
                //绘制风车图片
	        canvas.drawBitmap(bitMap, matrix,paint);

	        super.onDraw(canvas);
	    }

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_MOVE://随着手指的move而不断进行重绘,进而让风车转动起来
                        postInvalidate();//调用方法进行重绘
			break;
		}
		return true;
	}

}

上面的代码很简单,主要对MotionEvent.ACTION_MOVE事件进行捕获,并调用postInvalidate方法来实现重绘,在onDraw方法中通过Martix的变化来实现风车的旋转效果。在这里要注意:

1)onTouchEvent要返回true否则不会进行执行你在这个方法里面写的程序,具体原因见android事件拦截机制

在配置文件里面使用如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffffff"
    >

    <rotation.demo.view.RotationView
        android:id="@+id/rotationView"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_centerInParent="true">
    </rotation.demo.view.RotationView >

</RelativeLayout>
public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		RotationView rotation = (RotationView)findViewById(R.id.rotationView);
		BitmapDrawable drawable = (BitmapDrawable) getResources().getDrawable(R.drawable.fengche);
		rotation.setBitMap(drawable.getBitmap());
		rotation.initSize();
	}
}

经过运行会发现有个问题:不论是手指是顺时针还是逆时针风车运动的方向总是逆时针,经过测试发现当matrix.preRotate中的三处逐步变大的时候

就是顺时针转动,如果主键变小的话就是逆时针,所以我简单的添加了个两个按钮来选择是否是逆时针顺时针,当逆时针的时候让rad变量递减,顺时针递增就可以了。为此在RotationView里面增加了clockWise这个布尔变量,通过点击两个按钮的变量改变clockWise的值。效果图如下:

onDraw方法的代码改动如下:

private boolean clockWise = false;
@Override
	protected void onDraw(Canvas canvas) {

		Matrix matrix = new Matrix();
		// 设置转轴位置
		matrix.setTranslate((float) width / 2, (float) height / 2);
		if(clockWise) {//如果是顺时针
			rad+= 30;
		}else {
			rad-= 30;
		}
		// 开始转
		matrix.preRotate(degree);
		// 转轴还原
		matrix.preTranslate(-(float) width / 2, -(float) height / 2);

		// 将位置送到view的中心
		// matrix.postTranslate((float)(width) / 2, (float)(height) / 2);

		canvas.drawBitmap(bitMap, matrix, paint);

		super.onDraw(canvas);
	}

经过简单的修改,版本2就这么诞生了,当然版本2.0还有些问题,留给版本3解决,详见自定义View之大风车系列demo(2)

时间: 2024-10-16 04:15:28

自定义View之大风车系列demo(一)的相关文章

自定义View之大风车系列demo(二)

版本1.0和版本2.0的风车有个不尽人意的效果:当手指抬起的时候风车就会停止转动,现在版本3要做的就是让手指抬起的时候让风车继续转动一段时间,思路如下: 1)手指抬起的时候继续让风车转动5秒 2)需要监听MotionEvent.ACTION_UP事件并记录手指抬起的时间upTime 3)捕获MotionEvent.ACTION_UP事件并重绘五秒钟 根据上面的说明RotationView的代码做了如下的改变(在版本2的基础上主要修改了onTouchEvent事件: /**手指抬起的时间**/  

自定义View之大风车系列demo(三)

大风车系列版本1.0到版本3.0的体验有很大的不足:风车旋转的弧度都是手动写死的,不会根据手指移动的快慢而快慢.版本4.0将解决这个问题,思路如下: 1)以风车图片的中心为坐标原点简历一个直角坐标系,捕获手指按下事件也即是MotionEvent.ACTION_DOWN事件,记录此时手指的坐标点与直角坐标系x正坐标轴的夹角 2)获取手指移动的时候当前手指坐标点与直角坐标系x正轴的夹角. 3)计算步骤1和步骤2的两个夹角的差,就是手指此时移动的弧度.而不像版本3.0之前的那样写死了 具体代码设计如下

自定义View之大风车系列demo(四)

版本4.0有个问题当手指抬起的时候风车停止了,现在就解决这个问题,手指抬起的时候继续让风车由于惯性而继续旋转一段时间.思路如下 1)需要获取手指抬起时风车转动的瞬间速度,这个难度不小,在我的demo里面我只是简单的计算了手指按下到抬起经过的时间和弧度差,用弧度差除以时间来模拟下速度. 具体的还真不好用语言描述,所以偷个懒,直接上代码吧速度控制器添加了speed变量,并根据弧度差和经过的时间来计算速度 package rotation.demo.bean; import android.util.

自定义View系列教程07--详解ViewGroup分发Touch事件

自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 PS:如果觉得文章太长,那就直接看视频吧 在上一篇中已经分析完了View对于Touch事件的处理,在此基础上分析和理

自定义View系列教程05--示例分析

自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 PS:如果觉得文章太长,那就直接看视频吧 之前结合源码分析完了自定义View的三个阶段:measure,layout,draw. 那么,自定义有哪几种常见的方式呢? 直接继承自View 在使用该方式实现自定义View时通常的核心操作都在onDraw

自定义View系列教程01--常用工具介绍

在自定义View的时候,常常会用到一些Android系统提供的工具.这些工具封装了我们经常会用到的方法,比如拖拽View,计算滑动速度,View的滚动,手势处理等等.如果我们自己去实现这些方法会比较繁琐,而且容易出一些bug.所以,作为自定义View系列教程的开端,先介绍一下这些常用的工具,以便在后续的学习和工作中使用. Configuration ViewConfiguration GestureDetector VelocityTracker Scroller ViewDragHelper

自定义View之Chart图标系列(1)——点阵图

最近要做一些图表类的需求,一开始就去github上看了看,发现开源的图表框架还是蛮多的,但是很少有完全符合我的需求的,另外就是使用起来比较麻烦,所以就决定自己来造轮子了~~~ 今天要介绍的就是Android图标系列中点阵图(姑且这么叫着吧╮(╯▽╰)╭)的画法. 效果图如下: 需求: 1. 给出几个点 画出坐标轴(用虚线) 2. 画出对应的点 在点的上方标出数值 3. 下方要显示个数值表示的意义 4. 重点!!!!动态计算坐标轴,多余的坐标不能显示. 前三条好理解,第四条啥意思呢~ (比如说,我

wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果

上一篇介绍了贝塞尔曲线的简单应用 仿360内存清理效果 这一篇带来一个  两条贝塞尔曲线的应用 : 仿qq未读消息去除效果. 转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50503630 老规矩,先上效果图: qq的未读消息去除很炫酷,其实就是用了两条贝塞尔曲线,我们按思路来,先来画两个圆,及两条贝塞尔曲线,辅助点为圆心y坐标的一半.我们把下面移动的圆,叫做mMoveCircle. 这样一画,就很简单明了了对不对.只要在拖动的时候

自定义View基础 - 最易懂的自定义View原理系列(1)

前言 自定义View原理是Android开发者必须了解的基础: 在了解自定义View之前,你需要有一定的知识储备: 本文将全面解析关于自定义View中的所有知识基础. 目录 1. View的分类 视图View主要分为两类: 类别 解释 特点 单一视图 即一个View,如TextView 不包含子View 视图组 即多个View组成的ViewGroup,如LinearLayout 包含子View 2. View类简介 View类是Android中各种组件的基类,如View是ViewGroup基类