安卓自定义控件(view)
安卓自定义view
一、自定义View
- 优点:控件最*的实现方法,能*控制整个View的实现
- 缺点:比较复杂,需要正确测量View的尺寸
手动绘制各种视觉效果、工作量大
本次学习的内容就是通过继承View来实现一个简单的ImageView,它能够根据用户设置的大小使得图片在任何尺寸下都能正常显示。
下面先上效果图片:
1.首先创建继承自View的SimpleView类
package com.example.customviewapplication;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
public class SimpleView extends View {
private Paint mBitmapPaint;
private Drawable mDrawable;
private int mWidth;
private int mHeight;
public SimpleView(Context context) {
this(context,null);
}
public SimpleView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SimpleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(attrs);
mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);
}
private void initAttrs(AttributeSet attrs) {
if(attrs !=null){
//首先赋值
TypedArray array = null;
try{
array =
getContext().obtainStyledAttributes(attrs,R.styleable.SimpleImageView);
//根据图片id获取到drawable对象
mDrawable = array.getDrawable(R.styleable.SimpleImageView_src);
//测量drawable对象的宽高
measureDrawable();
}finally {
if (array != null) {
//然后回收
array.recycle();
}
}
}
}
在构造函数中获取该控件的属性,初始化要绘制的图片与画笔。
2.在Values目录下新建attr.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SimpleImageView">
<attr name="src" format="integer" />
</declare-styleable>
</resources>
3.在我们的activity_main.xml中引入我们的attr.xml文件,并且设置图片资源
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.customviewapplication.SimpleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:src = "@drawable/pic_2"/>
</LinearLayout>
4.测量图片的大小
private void measureDrawable() {
if(mDrawable == null){
throw new RuntimeException("drawable不能为空");
}
mWidth = mDrawable.getIntrinsicWidth();
mHeight = mDrawable.getMinimumHeight();
}
当我们运行程序时,首先会从布局信息中解析SimpleView,获取属性,进入SimpleView后会首先调用initAttrs函数进行初始化。
mWidth、mHeight分别表示视图的宽度、高度。我们在xml文件中对应的Drawable得到了图片的宽高,图片有多大,我们的SimpleView就多大。在SimpleView被加载的时候,会调用onMeasuer函数来测量大小,然后再绘制
5.绘制视图内容
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//设置图片的宽高
setMeasuredDimension(mWidth,mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
if (mDrawable == null) {
return;
}
//绘制图片
canvas.drawBitmap(ImageUtils.drawableToBitmap(mDrawable),
getLeft(),getTop(),mBitmapPaint);
}
到这一步就可以运行我们的程序了。
二、View尺寸的测量
为了支持用户自定义设置宽与高 我们需要根据用户的设置测量View的尺寸。效果如下图:
1.我们继续继续使用上文代码,这里我们要对onMeasure改写
定义变量
private int mWidth;
private int mHeight;
改写
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//宽度模式与大小
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
//高度模式与大小
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//设置view的宽高
setMeasuredDimension(measureWidth(widthMode,width),measureHeight(heightMode,height));
}
private int measureWidth(int mode, int width) {
switch (mode){
case MeasureSpec.UNSPECIFIED:
case MeasureSpec.AT_MOST:
break;
case MeasureSpec.EXACTLY:
mWidth = width;
break;
}
return mWidth;
}
private int measureHeight(int mode, int height) {
switch (mode){
case MeasureSpec.UNSPECIFIED:
case MeasureSpec.AT_MOST:
break;
case MeasureSpec.EXACTLY:
mHeight = height;
break;
}
return mHeight;
}
在onMeasure函数中获取宽、高的模式与大小后,分别调用measureWidth、measureHeight函数根据MeasureSpec的mode与大小计算View的具体大小。在MeasureSpec.AT_MOST
与MeasureSpec.UNSPECIFIED类型中,讲View的宽度高度设置为图片的宽度高度,当用户指定时,他的模式为EXACTLY,这样就会根据View的大小重新创建一个图片。
2.修改绘制代码
private Bitmap mBitmap;
@Override
protected void onDraw(Canvas canvas) {
if (mBitmap == null) {
mBitmap = Bitmap.createScaledBitmap(ImageUtils.drawableToBitmap(mDrawable),
getMeasuredWidth(),getMeasuredHeight(),true);
}
//绘制图片
canvas.drawBitmap(mBitmap,getLeft(),getTop(),mBitmapPaint);
}
三、Canvas与Paint(画布与画笔)
简单的在视图中绘制一个竖向文本,
//保存画布状态
canvas.save();
//旋转90度
canvas.rotate(90);
//绘制文字
mBitmapPaint.setColor(Color.YELLOW);
mBitmapPaint.setTextSize(300);
canvas.drawText("黑猫警长",getLeft() +50,getTop() -50,mBitmapPaint);
canvas.restore();
这里有一个问题,drawText函数默认是横向绘制的,为了达到我们预期的效果,需要首先将画布旋转90度,这时候原点在左下角,向右方向x递增,向下则为y递增。假设原点为0,那么文本起始坐标就为(50,-50),x越大越靠右,y越小就越向上偏移。绘制完文本之后再将画布还原,此时就能得到我们想要的效果了!
git代码地址:
上一篇: Xcode 6.3 Beta发布,Swift 1.2带来哪些新变化?
下一篇: 邮件功能中的那些事
推荐阅读
-
Android自定义控件:图形报表的实现(折线图、曲线图、动态曲线图)(View与SurfaceView分别实现图表控件)
-
安卓自定义流程进度图控件实例代码
-
实现安卓控件动画GridView
-
安卓开发笔记(二十八):仿写IOS switch选择器控件实现,checkbox
-
安卓三种动画之一View Animation与 案例 为活动的载入与退出添加动画
-
安卓常用View(视图开发技巧总结)
-
安卓开发入门教程-UI控件_Switch
-
自定义view进阶-贝塞尔曲线实现水波动画、粘性控件
-
安卓自定义View雷达图(蜘蛛图)教程
-
React Native学习教程之Modal控件自定义弹出View详解