【Android学习】自定义View的实现----以圆形图片控件为例
来源:互联网 发布:真实二手房源 知乎 编辑:程序博客网 时间:2024/05/18 03:14
在Android开发过程中,系统提供的控件有时并不能满足要求,往往需要通过自定义控件来实现需求。今天我们以圆形图片控件为例,简单介绍下它的具体实现方式
自定义控件的三种实现方式
- 组合控件
组合控件,简单说来就是将系统的一些控件组合成一个新的控件便于使用。譬如常见的标题栏控件,如图
最上一排中左边的返回按钮,中间的标题(自己的手机厚码)以及右边的其余功能按钮(弹出一个消息框)就是一个典型的组合控件
3. 自绘控件
自绘控件就是自己绘制的控件,主要是在View的onDraw方法中实现
3. 继承控件
继承控件继承系统已有的控件,在原有控件的属性上,引入新的属性以满足需求
我们今天的圆形图片控件就是结合上述的方法2.3实现。
定义自定义控件步骤
- 自定义View属性
- 从构造方法中获得自定义的View属性
- 重写onDraw以及onMeasure
- 使用自定义控件
自定义View属性
首先,在res/values中声明我们这个控件样式以及相关属性
一般说来的话attr.xml这个文件声明的都是view的相关信息,如果没有可以新建,也可以在别的xml文件中声明。
我这边的项目是要开发一个登录功能的界面,需要这个控件作为头像。因此,需要自定义的一些属性是这个头像的边框颜色以及宽度。具体代码如下。
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="borderColor" format="color" /> <attr name="borderWidth" format="dimension" /> <declare-styleable name="RoundImageView"> <attr name="borderColor" /> <attr name="borderWidth" /> </declare-styleable> </resources> View attrs_imageviewplus.xml
format中color表示颜色值,dimension表示尺寸值,其他的格式不再赘述。
从构造方法中获得自定义View的属性
新建一个RoundImageView类,继承ImageView,正如我们上面所述的这是一种继承控件(好像由于版本原因,单单继承ImageView无法正常显示,Android Studio自身给我提供了这样一个新的继承android.support.v7.widget.AppCompatImageView,可以使用)
public class RoundImageView extends android.support.v7.widget.AppCompatImageView{ private Paint mPaintBitmap = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint mPaintBorder = new Paint(Paint.ANTI_ALIAS_FLAG); private Bitmap mRawBitmap; private BitmapShader mShader; private Matrix mMatrix = new Matrix(); ...
之后是在构造方法中获取我们刚刚定义的新的属性
private static final int DEFAULT_BORDER_COLOR = Color.TRANSPARENT; private static final int DEFAULT_BORDER_WIDTH = 0; public ImageViewPlus(Context context, AttributeSet attrs) { super(context, attrs); // 从attrs.xml文件中读取我们对RoundImageView的配置信息 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ImageViewPlus); mBorderColor = ta.getColor(R.styleable.ImageViewPlus_borderColor, DEFAULT_BORDER_COLOR); mBorderWidth = ta.getDimensionPixelSize(R.styleable.ImageViewPlus_borderWidth, dip2px(DEFAULT_BORDER_WIDTH)); ta.recycle(); } ...
重写onDraw以及onMeasure
在View实现之前,View会先做一次测量,算出自己需要占用多大的面积,是一个Measure过程。View给我们提供了onMeasure的接口去实现测量方法,这个重写是可选的,今天这个空间并不需要,我们需要重写的是绘制接口onDraw,代码如下。
@Override protected void onDraw(Canvas canvas) { Bitmap rawBitmap = getBitmap(getDrawable()); if (rawBitmap != null){ int viewWidth = getWidth(); int viewHeight = getHeight(); int viewMinSize = Math.min(viewWidth, viewHeight); float dstWidth = viewMinSize; float dstHeight = viewMinSize; if (mShader == null || !rawBitmap.equals(mRawBitmap)){ mRawBitmap = rawBitmap; mShader = new BitmapShader(mRawBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); } if (mShader != null){ mMatrix.setScale((dstWidth - mBorderWidth * 2) / rawBitmap.getWidth(), (dstHeight - mBorderWidth * 2) / rawBitmap.getHeight()); mShader.setLocalMatrix(mMatrix); } mPaintBitmap.setShader(mShader); mPaintBorder.setStyle(Paint.Style.STROKE); mPaintBorder.setStrokeWidth(mBorderWidth); mPaintBorder.setColor(mBorderColor); float radius = viewMinSize / 2.0f; canvas.drawCircle(radius, radius, radius - mBorderWidth / 2.0f, mPaintBorder); canvas.translate(mBorderWidth, mBorderWidth); canvas.drawCircle(radius - mBorderWidth, radius - mBorderWidth, radius - mBorderWidth, mPaintBitmap); } else { super.onDraw(canvas); } } private Bitmap getBitmap(Drawable drawable){ if (drawable instanceof BitmapDrawable){ return ((BitmapDrawable)drawable).getBitmap(); } else if (drawable instanceof ColorDrawable){ Rect rect = drawable.getBounds(); int width = rect.right - rect.left; int height = rect.bottom - rect.top; int color = ((ColorDrawable)drawable).getColor(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawARGB(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color)); return bitmap; } else { return null; } } private int dip2px(int dipVal) { float scale = getResources().getDisplayMetrics().density; return (int)(dipVal * scale + 0.5f); }}
关于代码中的一些解释:
mMatrix.setScale与mShader.setLocalMatrix主要是为了保证图片在不同尺寸的手机大小下,固定大小的头像能够自适应缩放来吻合背景。
mPaintBitmap.setShader决定了圆形中的具体内容,而canvas.drawCircle 决定了画出来的形状是圆形
边框的实现则是先用实心纯色的Paint画了一个圆边,再在其中画圆形图片
使用自定义控件
最后就可以在我们的布局中使用我们自定义的控件拉,贴一下我自己的布局与效果图,大家可以做一下参考
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="10" /><RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1"> <com.example.aaron_zrrrrr.gcms.view.RoundImageView android:id="@+id/roundImageView" android:layout_centerInParent="true" android:layout_width="150dp" android:layout_height="150dp" android:src="@drawable/login" /></RelativeLayout><LinearLayout android:id="@+id/accountRel" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:orientation="horizontal" android:layout_weight="2"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> <EditText android:id="@+id/account" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="2" android:hint="account" android:textSize="15sp" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /></LinearLayout><LinearLayout android:id="@+id/pwdRel" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:orientation="horizontal" android:layout_weight="2"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> <EditText android:id="@+id/pwd" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="2" android:hint="account" android:textSize="15sp" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /></LinearLayout><LinearLayout android:id="@+id/loginRel" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:orientation="horizontal" android:layout_weight="2"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:id="@+id/login" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="2" android:hint="Login" android:textSize="15sp" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" /></LinearLayout><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="30" /></LinearLayout>
丑丑的登录界面OuO
参考源码:http://www.cnblogs.com/snser/p/5159126.html
- 【Android学习】自定义View的实现----以圆形图片控件为例
- 完美实现Android自定义控件---以自定义带图片和文本的Button为例
- 自定义View实现Android圆形图片
- Android自定义View实现不断旋转的圆形图片
- 圆形图片的实现自定义view
- 以自定义圆形进度条为例阐述自定义view步骤
- Android自定义view圆形图片
- Android圆形图片--自定义控件
- Android圆形图片自定义控件
- android-自定义圆形图片控件
- Android圆形图片--自定义控件
- Android圆形图片--自定义控件
- android 自定义控件 圆形图片
- Android圆形图片--自定义控件
- Android圆形图片--自定义控件
- Android--自定义View加载网络图片,实现缩放,圆形剪裁
- Android自定义控件View(圆形控件)
- Android中使用自定义的view实现圆形图片的效果
- ScrollView嵌套Listview,你会遇到的问题(1)!
- Alfresco文档管理系统 文档
- 决策树算法原理及案例
- android 自定义viewPager 下标
- http请求
- 【Android学习】自定义View的实现----以圆形图片控件为例
- 小飞鱼二开 使用jwt TOKEN方式单点登录开发(代码)
- spark的rdd.saveastextfile可以追加写入hdfs吗
- tomcat异常:Illegal access: this web application instance has been stopped already. Could not load ...
- 关于 struts2 Unable to load configuration.
- 用U盘安装Ubuntu系统,但不知道如何设置U盘启动
- Oracle索引与视图的创建与应用
- django 中验证码登录验证的实现
- 自学qt之 事件