Android 自定义控件(一)

摘要:
位图配置RGB _ 8888:位图配置RGB _ 565;//采用可绘制81Bitmapbitmap=Bitmap.createBitmap//的颜色格式创建相应的位图82Canvascanvas=newCanvas//创建与位图对应的画布83drawbable.setBounds;84可绘制。绘制;//将可绘制内容绘制到画布85returnbitmap中;86}87}在values/arrt.xml 1中定义的属性代码2345678仅定义一个src的塑料属性。使用我们的自定义ImageView控件1˂?

本文用一个简单的例子来说明一下自定义控件的步骤实现,自定义控件有几种实现类型,分别为继承自view完全自定义,继承现有的

控件实现特定效果,继承viewgroup实现布局类等;

本文研究的是继承自view完全自定义控件、下面继承view来实现一个简单的ImageView

步骤:

1、继承自view创建自定义控件

2、如果有需要的自定义view属性,在values/attrs.xml中定义属性集

3、在xml中引入命名控件、设置属性

4、在代码中读取xml中的属性,初始化视图

5、测量视图大小

6、绘制视图内容

示例代码如下

首先继承自view创建自定义控件

 1 package com.jiao.simpleimageview.view;
 2 
 3 import android.content.Context;
 4 import android.content.res.TypedArray;
 5 import android.graphics.Bitmap;
 6 import android.graphics.Canvas;
 7 import android.graphics.Paint;
 8 import android.graphics.PixelFormat;
 9 import android.graphics.drawable.Drawable;
10 import android.util.AttributeSet;
11 import android.view.View;
12 
13 import com.jiao.simpleimageview.R;
14 
15 /**
16  * Created by jiaocg on 2016/3/22.
17  */
18 public class SimpleImageView extends View {
19     private Paint mBitmapPaint;
20     private Drawable mDrawable;
21     private int mWidth;
22     private int mHight;
23 
24     public SimpleImageView(Context context) {
25         this(context, null);
26     }
27 
28 
29     public SimpleImageView(Context context, AttributeSet attrs) {
30         super(context, attrs);
31 
32         //根据属性初始化
33         initAttrs(attrs);
34         mBitmapPaint = new Paint();
35         mBitmapPaint.setAntiAlias(true);//抗锯齿
36     }
37 
38     //读取xml中定义的属性  初始化视图
39     private void initAttrs(AttributeSet attrs) {
40         if (attrs != null) {
41 
42             TypedArray array = null;
43             //获取我们在attr文件中定义的属性集合
44             array = getContext().obtainStyledAttributes(attrs, R.styleable.SimpleImageView);
45             //根据图片id获取到drawable
46             mDrawable = array.getDrawable(R.styleable.SimpleImageView_src);
47             measureDrawable();
48         }
49     }
50 
51     //测量视图大小
52     private void measureDrawable() {
53 
54         if (mDrawable == null)
55             throw new RuntimeException("Drawable不能为空");
56 
57         mWidth = mDrawable.getIntrinsicWidth();
58         mHight = mDrawable.getIntrinsicHeight();
59     }
60 
61     //测量视图大小
62     @Override
63     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
64         setMeasuredDimension(mWidth, mHight);
65     }
66 
67     //绘制视图内容
68     @Override
69     protected void onDraw(Canvas canvas) {
70         if (mDrawable == null) {
71             return;
72         }
73         canvas.drawBitmap(drawableToBitmap(mDrawable), getLeft(), getTop(), mBitmapPaint);
74     }
75 
76     // drawable 转换成bitmap
77     private Bitmap drawableToBitmap(Drawable drawable) {
78         int width = mWidth;
79         int height = mHight;
80         Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;// 取drawable的颜色格式
81         Bitmap bitmap = Bitmap.createBitmap(width, height, config);// 建立对应bitmap
82         Canvas canvas = new Canvas(bitmap);// 建立对应bitmap的画布
83         drawable.setBounds(0, 0, width, height);
84         drawable.draw(canvas);// 把drawable内容画到画布中
85         return bitmap;
86     }
87 }

定义在values/arrt.xml中的属性代码

1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3     <declare-styleable name="SimpleImageView">
4 
5     <attr name="src" format="integer" />
6     </declare-styleable>
7 
8 </resources>

只定义了一个src的整形属性

使用我们自定义的ImageView控件

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:img="http://schemas.android.com/apk/res/com.jiao.simpleimageview"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent">
 6 
 7 
 8     <com.jiao.simpleimageview.view.SimpleImageView
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         img:src="http://t.zoukankan.com/@mipmap/main_pic">
12 
13     </com.jiao.simpleimageview.view.SimpleImageView>
14 
15 </RelativeLayout>

注意:在使用自定义属性时,我们需要将该属性所在的命名控件引入到xml中,命名控件实际上就是该工程的包名,如上述代码标亮部分

xmlns:名字="http://schemas.android.com/apk/res/应用包名"

运行效果如下:
Android 自定义控件(一)第1张

 以上是简单的实现了一个ImageView控件的功能,但是还不够完善,因为控件的大小等于图片的实际大小,我们应该

让控件更灵活可以实现match_parent、warp_content、或者用户指定宽高,要想实现这样的功能我们先来理解一个概念

我们自定义的控件在绘制的时候回调用OnMeasure()方法,该方法接受两个参数:widthMeasureSpec和heightMeasureSpec

这两个值用来确定视图的大小和模式,MeasureSpec的值是由specSize和specMode共同组成,其中specSize是大小specMode是

规格,下面说一下specMode的三种规格:

1、EXACTLY:match_parent模式,父视图希望子视图的大小应该是由specSize来决定的,可以是任意大小或者match_parent

2、AT_MOST:warp_content模式,子视图最多只能是specSize指定的大小,并且肯定不能超过specSize的大小

3、UNSPECIFIED:没有任何限制,可以任意设置,一般不用

通过以上的分析我们可以知道,在我们自定义控件测量的时候,我们就可以通过这两个参数:widthMeasureSpec和heightMeasureSpec

来得知控件的大小和规格因此我们只需要在代码中进行判断就可以更灵活的控制控件的大小,具体代码如下:

只贴出了关键代码,就是在以上代码中进行了修改,只修改了OnMeasure()方法中的逻辑

 1   //测量视图大小
 2     @Override
 3     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 4 //        setMeasuredDimension(mWidth, mHight);
 5 
 6         //根据widthMeasureSpec的值来获取控件的显示模式和宽度
 7         int widthMode = MeasureSpec.getMode(widthMeasureSpec);
 8         int widthSize = MeasureSpec.getSize(widthMeasureSpec);
 9 
10         //根据heightMeasureSpec的值来获取控件的显示模式和高度
11         int hightMode = MeasureSpec.getMode(heightMeasureSpec);
12         int hightSize = MeasureSpec.getSize(heightMeasureSpec);
13 
14         setMeasuredDimension(measureWidth(widthMode, widthSize), measureHight(hightMode, hightSize));
15     }
16 
17 
18     private int measureWidth(int mode, int width) {
19         switch (mode) {
20             case MeasureSpec.UNSPECIFIED://未定义模式  一般不用
21             case MeasureSpec.AT_MOST://warp_content模式
22                 break;
23             case MeasureSpec.EXACTLY://match_parent模式或指定大小时的模式
24                 mWidth = width;
25                 break;
26         }
27 
28         return mWidth;
29     }
30 
31     private int measureHight(int mode, int hight) {
32         switch (mode) {
33             case MeasureSpec.UNSPECIFIED://未定义模式  一般不用
34             case MeasureSpec.AT_MOST://warp_parent模式
35                 break;
36             case MeasureSpec.EXACTLY://match_parent模式或指定大小时的模式
37                 mHight = hight;
38                 break;
39         }
40         return mHight;
41     }

首先我们通过OnMeasure方法中的两个参数来获取控件的大小和规格,然后我们根据大小和规格知道用户想要什么样

大小的控件,通过measureWidth和measureHight两个方法根据控件的规格,从而设置控件的大小;

以下分别是warp_content  120*180  match_parent的三种效果示意图:

Android 自定义控件(一)第2张Android 自定义控件(一)第3张Android 自定义控件(一)第4张

免责声明:文章转载自《Android 自定义控件(一)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇重定向(Redirect)和请求转发(Forward)1046下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

如何使用 window.open() 下载文件: 在本页面打开并防止浏览器拦截

从接口请求返回的内容有两种类型:直接返回文件内容、返回url和使用窗口。open()直接打开请求地址或返回的url,然后将请求地址或所返回的url直接分配给窗口的href1。直接返回文件内容:打开请求api地址downPkg(){letmywin=window.open('',mywin.location.href=apiPath;}2。返回url时:...

kibana数据操作

ES中的索引数据将存储为_分数:分数越高,匹配越好。即使Lucene使用了反向索引,计算搜索得分仍需要一些时间。②.— 筛选器上下文:使用筛选器参数时的执行环境,例如在布尔查询中使用Must _ Not或Filter。在筛选器上下文中,查询将回答此问题...

微信小程序使用weui构建搜索栏(searchbar)+导航(navbar)

首先需要在lib目录中添加weui.wxss。searchbar和navbar结合主要解决两者的层次问题,即搜索框输入时,下方的检索结果能够覆盖住navbar。下面就开始发码啦:wxml部分:0}}"bindtap="clearInput"˃搜索˂viewclass="weui-search-bar__cancel-btn"hidden="{{!...

html2canvas踩坑日记

在html2canvas&lt;html2canvas(document.querySelector(“#capture”)).then(canvas=&gt;{document.body.appendChild(canvas)});//图片地址是文档。身体appendChild(画布);...

PLSQL操作Oracle创建用户和表(含创建用户名和密码)

1》 打开PLSQL,填写用户名和密码,为数据库选择ORCL2,成功登录后可以在界面顶部看到以下信息system@ORCL这意味着用户系统处于登录状态。菜单栏中的会话可以登录和注销。...

flutter vscode+第三方安卓模拟器

1.首先打开夜曲模拟器2.Win+R,选择cmd,在第三方模拟器安装目录的bin目录下输入夜曲模拟器,然后运行命令:nox_Adb.execonnect127.0.0.1:620013。打开项目终端的vscode并建立连接:adbconnect127.00.1:62001(夜神模拟器的默认端口)4。查看连接:adbdevices或不使用第三方模拟器:1.打开...