赞
踩
在Android的开发中,很多时候系统提供的View已经不能够满足我们的要求,自定义View的需求自然而然就出来了。
实现自定义的View,其实就是去扩展View类,重写其某些方法函数,把原来由Android Framework 实现的东西,让我们自己来实现自己想要的某些效果。
其本质上就是封装了一些自己想要的效果,并使之能够被Framework识别,跟普通的系统的控件一样,可以重复利用。
下面就拿一个例子开始吧,先上一张效果图:
在这里,有六个正方形的View,每一个View的背景颜色都不一样,图片也不一样,旋转的角度也不一样,其实这三个都是自定义的属性来的。
1. 自定义属性。
在 res/values/文件夹中创建一个 attrs.xml 文件,定义我们的属性。
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="CustomRotateView">
- <attr name="drawable" format="reference"/>
- <attr name="degree" format="float" />
- <attr name="bgcolor" format="color" />
- </declare-styleable>
- </resources>
2. 定义好自定义属性之后,开始创建自定义的View。
很显然,一切得从继承View开始,代码如下:
- package com.example.apidemostudy;
-
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Matrix;
- import android.graphics.PixelFormat;
- import android.graphics.drawable.Drawable;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.View;
-
- public class CustomRotateView extends View {
-
- private final static String tag = "com.example.apidemostudy.CustomRotateView";
-
- private Bitmap mBitmap; // The bitmap to be drawn
-
- private int bgColor; // the BackgroundColor
-
- private float degree; // the angels to rotate
-
- private Matrix matrix; // the matrix to transform
-
- private int mWidth = 240, mHeight = 240; // The RotateImageView's height and
- // width
-
- private int mPivotX, mPivotY; // the pivot point to rotate by
-
- private int mTranslateX, mTranslateY; // the translation to center in
- // current view
-
- /**
- * Constructor, called when inflate the xml definition
- *
- * @param context
- * @param attrs
- */
- public CustomRotateView(Context context, AttributeSet attrs) {
- super(context, attrs);
- Log.v(tag, "CustomRotateView Initializing");
- TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.CustomRotateView);
- Drawable drawable = typedArray.getDrawable(R.styleable.CustomRotateView_drawable);
- degree = typedArray.getFloat(R.styleable.CustomRotateView_degree, 0);
- bgColor = typedArray.getColor(R.styleable.CustomRotateView_bgcolor,Color.YELLOW);
- typedArray.recycle();
-
- // Change to the drawable to bitmap and zoom it until the diagnoal line
- // is shorter than the required width and height
- mBitmap = zoomBitmap(drawableToBitmap(drawable), mWidth, mHeight);
-
- // Rotate axis, the central point of the bitmap
- mPivotX = mBitmap.getWidth() / 2;
- mPivotY = mBitmap.getHeight() / 2;
-
- // translation, translate the bitmap to the center of this view
- mTranslateX = mWidth / 2 - mPivotX;
- mTranslateY = mHeight / 2 - mPivotY;
-
- matrix = new Matrix();
- }
-
- /**
- * Measure the current view set it to the fixed width and height. it's ok to
- * use the widthMeasureSpec and heightMeasureSpec if its size is decided by
- * its parent.
- */
- @Override
- public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(mWidth, mHeight);
- }
-
- /**
- * Draw the current view, 1) draw background color by bgColor 2) rotate the
- * bitmap 3) move the bitmap to center
- */
- @Override
- public void onDraw(Canvas canvas) {
-
- canvas.drawColor(bgColor);
- matrix.reset();
- matrix.postRotate(degree, mPivotX, mPivotY);
- matrix.postTranslate(mTranslateX, mTranslateY);
-
- canvas.drawBitmap(mBitmap, matrix, null);
-
- }
-
- /**
- * Zoom the bitmap to make sure it will be always displayed inside the view
- *
- * @param oldBitmap
- * @return
- */
- private Bitmap zoomBitmap(Bitmap oldBitmap, int reqWidth, int reqHeight) {
- Matrix pMatrix = new Matrix();
- int oldWidth = oldBitmap.getWidth();
- int oldHeight = oldBitmap.getHeight();
-
- double diagnoal = Math.sqrt(oldWidth * oldWidth + oldHeight * oldHeight);
- float scaleX = (float) (reqWidth / diagnoal);
- float scaleY = (float) (reqHeight / diagnoal);
-
- float scale = scaleX < scaleY ? scaleX : scaleY;
- pMatrix.postScale(scale, scale);
- Bitmap bitmap = Bitmap.createBitmap(oldBitmap, 0, 0, oldWidth,
- oldHeight, pMatrix, true);
-
- return bitmap;
- }
-
- /**
- * Change the drawable to Bitmap
- *
- * @param drawable
- * @return
- */
- private Bitmap drawableToBitmap(Drawable drawable) {
- int w = drawable.getIntrinsicWidth();
- int h = drawable.getIntrinsicHeight();
- Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
- : Bitmap.Config.RGB_565;
- Bitmap bitmap = Bitmap.createBitmap(w, h, config);
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, w, h);
- drawable.draw(canvas);
- return bitmap;
- }
-
- }
1)构造函数
CustomRotateView(Context context, AttributeSet attrs),从xml 中解析的view, 一定要有这个构造函数,包含有attributeSet 参数。
在构造函数中,做了几件事情:
第一,利用 TypedArray 获取自定义的属性,并将其中的drawable 转化为bitmap, 将其缩小到其对角线比当前View的宽跟高都要小,这样其在旋转角度的时候,就不会有些尖尖角角跑出这个View了。
第二,设定旋转的中心点和图片的偏移量,其实就是绕着图片中心转,然后将图片移到当前View的中心。
2)OnMeasure 函数
View 在被new 出来之后,并添加到布局去的时候,到其显示在窗口,让眼睛可以看到的过程中,其实是经过了三个步骤的,measure, layout 和 draw, 对于叶子View来说,不需要去关心layout, 因为这是由其父窗口来决定的,但是Measure过程和Draw过程,却是需要View也参与在其中的,学习Android 不久,详细的过程我目前没法很好地表达出来,各位可以自己在csdn 中找一下。
OnMeasure函数会决定当前的宽高是怎么样的,在这个例子中,简单地将当前的View 的宽高,设定为240, 240,一个正方形。
3) OnDraw 函数
当测量完当前的View 大小的时候,就是画内容了。在这里只是3.1)设置背景颜色 3.2)简单地利用matrix 作一个旋转和偏移。
3. 在布局文件中用上我们自定义的View
layout/custom_layout.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:custom="http://schemas.android.com/apk/res/com.example.apidemostudy"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
-
- <com.example.apidemostudy.CustomRotateView
- android:id="@+id/rotateView1"
- android:layout_width="240dip"
- android:layout_height="300dip"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- custom:bgcolor="#000000"
- custom:degree="0"
- custom:drawable="@drawable/photo1" />
-
-
- <com.example.apidemostudy.CustomRotateView
- android:id="@+id/rotateView2"
- android:layout_width="240dip"
- android:layout_height="300dip"
- android:layout_alignParentLeft="true"
- android:layout_below="@+id/rotateView1"
- custom:bgcolor="#FF0000"
- custom:degree="45"
- custom:drawable="@drawable/photo2" />
-
-
- <com.example.apidemostudy.CustomRotateView
- android:id="@+id/rotateView3"
- android:layout_width="240dip"
- android:layout_height="300dip"
- android:layout_alignParentLeft="true"
- android:layout_below="@+id/rotateView2"
- custom:bgcolor="#FFFF00"
- custom:degree="30"
- custom:drawable="@drawable/photo3" />
-
-
- <com.example.apidemostudy.CustomRotateView
- android:id="@+id/rotateView4"
- android:layout_width="240dip"
- android:layout_height="300dip"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- custom:bgcolor="#CCCCCC"
- custom:degree="60"
- custom:drawable="@drawable/photo4" />
-
-
- <com.example.apidemostudy.CustomRotateView
- android:id="@+id/rotateView5"
- android:layout_width="240dip"
- android:layout_height="300dip"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/rotateView4"
- custom:bgcolor="#777777"
- custom:degree="-30"
- custom:drawable="@drawable/photo5" />
-
-
- <com.example.apidemostudy.CustomRotateView
- android:id="@+id/rotateView6"
- android:layout_width="240dip"
- android:layout_height="300dip"
- android:layout_alignParentRight="true"
- android:layout_below="@+id/rotateView5"
- custom:bgcolor="#123456"
- custom:degree="-60"
- custom:drawable="@drawable/photo6" />
-
-
- </RelativeLayout>
首先要定义一个自定义的命名空间,跟系统 的命名空间区分开来,如:
xmlns:custom="http://schemas.android.com/apk/res/com.example.apidemostudy"
将上面的“Android” 字样替换成包名。
然后就是用上我们自定义的View了,用法很简单,就是直接拿着绝对路径放上去。
<com.example.apidemostudy.CustomRotateView
最后就是设置我们自定义的属性,
- custom:bgcolor="#000000"
- custom:degree="0"
- custom:drawable="@drawable/photo1"
4. 最后在Activity 中放上我们的布局文件,如下:
- public class CustomActivity extends Activity{
-
- protected void onCreate(Bundle savedInstanceState){
-
- super.onCreate(savedInstanceState);
- setContentView(R.layout.custom_layout);
- }
- }
嗯,自定义View 就是这样的,下一次写一个自定义的ViewGroup.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。