Android 自定义控件(一)
2016-03-23 17:10
477 查看
本文用一个简单的例子来说明一下自定义控件的步骤实现,自定义控件有几种实现类型,分别为继承自view完全自定义,继承现有的
控件实现特定效果,继承viewgroup实现布局类等;
本文研究的是继承自view完全自定义控件、下面继承view来实现一个简单的ImageView
步骤:
1、继承自view创建自定义控件
2、如果有需要的自定义view属性,在values/attrs.xml中定义属性集
3、在xml中引入命名控件、设置属性
4、在代码中读取xml中的属性,初始化视图
5、测量视图大小
6、绘制视图内容
示例代码如下
首先继承自view创建自定义控件
定义在values/arrt.xml中的属性代码
只定义了一个src的整形属性
使用我们自定义的ImageView控件
注意:在使用自定义属性时,我们需要将该属性所在的命名控件引入到xml中,命名控件实际上就是该工程的包名,如上述代码标亮部分
以上是简单的实现了一个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()方法中的逻辑
首先我们通过OnMeasure方法中的两个参数来获取控件的大小和规格,然后我们根据大小和规格知道用户想要什么样
大小的控件,通过measureWidth和measureHight两个方法根据控件的规格,从而设置控件的大小;
以下分别是warp_content 120*180 match_parent的三种效果示意图:
控件实现特定效果,继承viewgroup实现布局类等;
本文研究的是继承自view完全自定义控件、下面继承view来实现一个简单的ImageView
步骤:
1、继承自view创建自定义控件
2、如果有需要的自定义view属性,在values/attrs.xml中定义属性集
3、在xml中引入命名控件、设置属性
4、在代码中读取xml中的属性,初始化视图
5、测量视图大小
6、绘制视图内容
示例代码如下
首先继承自view创建自定义控件
package com.jiao.simpleimageview.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; import com.jiao.simpleimageview.R; /** * Created by jiaocg on 2016/3/22. */ public class SimpleImageView extends View { private Paint mBitmapPaint; private Drawable mDrawable; private int mWidth; private int mHight; public SimpleImageView(Context context) { this(context, null); } public SimpleImageView(Context context, AttributeSet attrs) { super(context, attrs); //根据属性初始化 initAttrs(attrs); mBitmapPaint = new Paint(); mBitmapPaint.setAntiAlias(true);//抗锯齿 } //读取xml中定义的属性 初始化视图 private void initAttrs(AttributeSet attrs) { if (attrs != null) { TypedArray array = null; //获取我们在attr文件中定义的属性集合 array = getContext().obtainStyledAttributes(attrs, R.styleable.SimpleImageView); //根据图片id获取到drawable mDrawable = array.getDrawable(R.styleable.SimpleImageView_src); measureDrawable(); } } //测量视图大小 private void measureDrawable() { if (mDrawable == null) throw new RuntimeException("Drawable不能为空"); mWidth = mDrawable.getIntrinsicWidth(); mHight = mDrawable.getIntrinsicHeight(); } //测量视图大小 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(mWidth, mHight); } //绘制视图内容 @Override protected void onDraw(Canvas canvas) { if (mDrawable == null) { return; } canvas.drawBitmap(drawableToBitmap(mDrawable), getLeft(), getTop(), mBitmapPaint); } // drawable 转换成bitmap private Bitmap drawableToBitmap(Drawable drawable) { int width = mWidth; int height = mHight; Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;// 取drawable的颜色格式 Bitmap bitmap = Bitmap.createBitmap(width, height, config);// 建立对应bitmap Canvas canvas = new Canvas(bitmap);// 建立对应bitmap的画布 drawable.setBounds(0, 0, width, height); drawable.draw(canvas);// 把drawable内容画到画布中 return bitmap; } }
定义在values/arrt.xml中的属性代码
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="SimpleImageView"> <attr name="src" format="integer" /> </declare-styleable> </resources>
只定义了一个src的整形属性
使用我们自定义的ImageView控件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:img="http://schemas.android.com/apk/res/com.jiao.simpleimageview" android:layout_width="match_parent" android:layout_height="match_parent"> <com.jiao.simpleimageview.view.SimpleImageView android:layout_width="wrap_content" android:layout_height="wrap_content" img:src="@mipmap/main_pic"> </com.jiao.simpleimageview.view.SimpleImageView> </RelativeLayout>
注意:在使用自定义属性时,我们需要将该属性所在的命名控件引入到xml中,命名控件实际上就是该工程的包名,如上述代码标亮部分
xmlns:名字="http://schemas.android.com/apk/res/应用包名" 运行效果如下:
以上是简单的实现了一个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()方法中的逻辑
//测量视图大小 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // setMeasuredDimension(mWidth, mHight); //根据widthMeasureSpec的值来获取控件的显示模式和宽度 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); //根据heightMeasureSpec的值来获取控件的显示模式和高度 int hightMode = MeasureSpec.getMode(heightMeasureSpec); int hightSize = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(measureWidth(widthMode, widthSize), measureHight(hightMode, hightSize)); } private int measureWidth(int mode, int width) { switch (mode) { case MeasureSpec.UNSPECIFIED://未定义模式 一般不用 case MeasureSpec.AT_MOST://warp_content模式 break; case MeasureSpec.EXACTLY://match_parent模式或指定大小时的模式 mWidth = width; break; } return mWidth; } private int measureHight(int mode, int hight) { switch (mode) { case MeasureSpec.UNSPECIFIED://未定义模式 一般不用 case MeasureSpec.AT_MOST://warp_parent模式 break; case MeasureSpec.EXACTLY://match_parent模式或指定大小时的模式 mHight = hight; break; } return mHight; }
首先我们通过OnMeasure方法中的两个参数来获取控件的大小和规格,然后我们根据大小和规格知道用户想要什么样
大小的控件,通过measureWidth和measureHight两个方法根据控件的规格,从而设置控件的大小;
以下分别是warp_content 120*180 match_parent的三种效果示意图:
相关文章推荐
- GitHub 上排名前 100 的 Android 开源库介绍
- 可滑动弹出菜单的自定义Layout,基于ViewGroup
- android的一些比较有用的方法
- layout_margin & padding
- 45.Android 第三方开源库收集整理(转)
- Android蓝牙开发全面总结
- Android开发60条技术经验总结
- Android View Touch的事件分发机制
- android提供的json解析类
- Android开发库VUtils之农历计算
- android中实现返回首页功能
- Android使用xml旋转图片,个人记录
- Android官方开发文档Training系列课程中文版:添加ActionBar之自定义ActionBar样式
- android——混淆打包
- 3月23日学习记录(showAsAction,android:orderInCategory="100")
- 【Android】【事件】onInterceptTouchEvent(),onTouchEvent()
- Android源代码的获取
- android解压zip格式的包
- 理解android:targetSdkVersion
- 关于Android中XML解析方式