Android自定义控件之自定义View(四)
来源:互联网 发布:c语言 static const 编辑:程序博客网 时间:2024/05/05 19:29
转载请注明出处:http://blog.csdn.net/xiaohao0724/article/details/61918934
穿插了几篇自定义控件热身之后,今天我们来继续学习自定义控件。
老规矩先上图:
OK,很简单吧,这个效果不用自定义控件也可以实现,只需要在ImageView外层包一个布局并把布局的背景设置成圆角的就可以了,那今天我们就用自定义View的方式来实现这个效果,并穿插介绍一下onMeasure的使用场景。
首先在value目录下面新建attr.xml自定义属性文件
<?xml version="1.0" encoding="utf-8"?><resources> <!-- 图片来源 --> <attr name="src" format="reference" /> <!-- 图片展示方式,在自定义View中控制 --> <attr name="scaleType"> <enum name="fitXY" value="1" /> <enum name="centerCrop" value="2" /> </attr> <!-- 圆角矩形的圆角大小 --> <attr name="corner" format="dimension" /> <declare-styleable name="BorderImageView"> <attr name="src" /> <attr name="scaleType" /> <attr name="corner" /> </declare-styleable></resources>
新建BorderImageView继承View
public class BorderImageView extends View {/**控件的宽*/private int width;/**控件的高*/private int height;/**控件中设置的图片*/private Bitmap bitmap;/**图片的展示方式*/private int scaleType;/**圆角矩形*/private RectF rectF;/**边框的圆角*/private int corner;/**画笔*/private Paint paint;private final int FIT_XY = 1;private final int CENTER_CROP = 2;public BorderImageView(Context context) {this(context, null);}public BorderImageView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public BorderImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.BorderImageView, defStyleAttr, 0);int indexCount = typedArray.getIndexCount();for (int i = 0; i < indexCount; i++) {int index = typedArray.getIndex(i);switch (index) {case R.styleable.BorderImageView_src:bitmap = BitmapFactory.decodeResource(getResources(), typedArray.getResourceId(i, 0));break;case R.styleable.BorderImageView_scaleType:scaleType = typedArray.getInt(i, 0);break;case R.styleable.BorderImageView_corner:corner = typedArray.getDimensionPixelSize(indexCount, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,20, getResources().getDisplayMetrics()));break;default:break;}}//回收typedArray.recycle();rectF = new RectF();paint = new Paint();paint.setAntiAlias(true);paint.setStrokeWidth(5.0f);paint.setStyle(Style.FILL);paint.setColor(Color.GREEN);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);rectF = new RectF(0, 0, getMeasuredWidth(), getMeasuredHeight());canvas.drawRoundRect(rectF, corner, corner, paint);rectF.left = getPaddingLeft();rectF.right = width - getPaddingRight();rectF.top = getPaddingTop();rectF.bottom = height - getPaddingBottom();if (scaleType == FIT_XY){canvas.drawBitmap(bitmap, null, rectF, paint);} else if(scaleType == CENTER_CROP){//计算居中的矩形范围rectF.left = width / 2 - bitmap.getWidth() / 2;rectF.right = width / 2 + bitmap.getWidth() / 2;rectF.top = height / 2 - bitmap.getHeight() / 2;rectF.bottom = height / 2 + bitmap.getHeight() / 2;canvas.drawBitmap(bitmap, null, rectF, paint);}}}
布局文件activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:havorld="http://schemas.android.com/apk/res/com.havorld.borderimageview" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.havorld.borderimageview.MainActivity" > <com.havorld.borderimageview.view.BorderImageView android:layout_width="300dp" android:layout_height="300dp" android:layout_margin="10dp" android:padding="10dp" havorld:scaleType="fitXY" havorld:corner="15sp" havorld:src="@drawable/ql" /></RelativeLayout>
运行效果如下图:
我们更改布局文件为:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:havorld="http://schemas.android.com/apk/res/com.havorld.borderimageview" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.havorld.borderimageview.MainActivity" > <com.havorld.borderimageview.view.BorderImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:padding="10dp" havorld:scaleType="fitXY" havorld:corner="15sp" havorld:src="@drawable/ql" /></RelativeLayout>
运行效果如下:
那么问题来了,我们明明设置的是wrap_content,为什么显示的效果却是match_parent的呢?
当我们在xml中把自定义控件设置为具体某一个值时控件显示效果为设置的确定值,当设置为match_parent或者wrap_content时显示都为match_parent。为了在设置为wrap_content时显示正确的大小我们需要重写onMeasure()方法重新测量控件的大小。
/** * 1、设置宽度 MeasureSpec.EXACTLY:精确模式.一般是设置了明确的值或者是 MATCH_PARENT * 在这种模式下,尺寸的值是具体值多少(如30dp),那么这个组件的长或宽就是多少。 * 父视图希望子视图的大小应该是specSize中指定的. * * 2、MeasureSpec.AT_MOST:最大模式.一般为 WARP_CONTENT * 这个也就是父组件,能够给出的最大的空间,当前组件的长或宽最大只能为这么大,当然也可以比这个小 * 。子视图的大小最多是specSize中指定的值,也就是说不建议子视图的大小超过specSize中给定的值. * * 3、MeasureSpec.UNSPECIFIED:未指定模式. * 这个就是说,当前组件可以随便用空间,不受限制,我们可以随意指定视图的大小(很少使用). * */@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec); //根据测量模式和测量值获取宽 width = getMeasuredLength(widthMeasureSpec, true); //根据测量模式和测量值获取高 height = getMeasuredLength(heightMeasureSpec, false); setMeasuredDimension(width, height);}private int getMeasuredLength(int measureSpec, boolean isWidth) {int size = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);int padding = isWidth ? getPaddingLeft() + getPaddingRight(): getPaddingTop() + getPaddingBottom();if (specMode == MeasureSpec.EXACTLY) { // 指定了确定的具体值或者match_parentsize = specSize;} else if (specMode == MeasureSpec.AT_MOST) { // 设置为wrap_contentsize = isWidth ? padding + bitmap.getWidth() : padding+ bitmap.getHeight();}size = Math.min(specSize, size);//如果图片超出屏幕,就设置为夫布局测量的尺寸return size;}
运行显示正如第一幅图所示效果图。
点击下载源码
0 0
- Android自定义控件之自定义View(四)
- Android自定义控件之自定义View(一)
- Android自定义控件之自定义View(二)
- 3.5.Android控件架构与自定义控件详解之自定义View(四)
- android自定义控件(四) View中的方法
- android自定义控件(四) View中的方法
- android自定义控件(四) View中的方法
- android自定义控件(四) View中的方法
- android自定义控件(四) View中的方法
- Android自定义控件 -- 自定义View
- Android 自定义View (四)
- Android 自定义View (四)
- Android进阶之自定义view(四)
- android 自定义 view 之ViewGroup(四)
- android 自定义view之继承(四)
- Android自定义View控件
- Android自定义View控件
- Android自定义View控件
- Android设置锁屏方式为无代码
- Linux 进程控制——等待队列详解(二)
- List中的数据如何根据对象的某一个或多个字段排序
- WebSphere Application Server8.5中Filter没有在Servlet之前初始化的解决方法
- scroolView嵌套listview时listView只显示一条item的高,并且还能滑动问题
- Android自定义控件之自定义View(四)
- 卖体验卖温度,年轻人家电印上“统帅烙印”
- 性能调优之:缓存
- 原生Ajax如何区别对待不同的http请求
- 【web开发 ES6新增语法】常用ES2015/ES6新增语法的使用
- java中的数据流
- mysql 从dump出来的sql文件导回去数据库里面
- 一遍记住Java常用的八种排序算法与代码实现
- Java中的多线程你只要看这一篇就好了