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

来源:互联网 发布:php 大端小端 转换 编辑:程序博客网 时间:2024/06/04 19:23

每次写博客最讨厌写博客的开头,不知道该写些什么,现在也是,感觉跟写八百字作文似的。之所以会写这一系列的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的宽和高,由于是正方形宽和高是一样的@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.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);    }@Overridepublic 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 {    @Overrideprotected 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;@Overrideprotected 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)


1 0
原创粉丝点击