今天我们来讲一下有关自定义控件的问题,今天讲的这篇是从布局自定义开始的,难度不大,一看就明白,估计有的同学或者开发者看了说,这种方式多此一举,但是小编我不这么认为,多一种解决方式,就多一种举一反三的学习。下一次或者过几天我会从自定义属性,在布局文件中使用属性的方式再讲一篇关于自定义控件的文章,希望对大家能够有所帮助。

昨天我们学习了自定义带图片和文字的ImageTextButton,非常简单,我承诺给大家要讲一下用自定义属性的方式学习真正的实现自定义控件,在布局文件中使用属性的方式就需要用到attr.xml这个文件,以前很多同学问我这个是干什么的,现在学了这篇内容,你就差不多知道了,以后就别再问了。自定义圆形控件 RoundImageView ,我相信大家在开发中会经常遇到设置圆形头像的情况,因为这样的头像显得漂亮。怎么做呢?先看效果图:

讲之前解释一下attr.xml的作用,我用土话废话说,这样容易理解:比如我自定义一个控件,怎么实现呢,以RoundImageView为例,首先是继承ImageView,然后实现其构造函数,在构造函数中,获取attr.xml中的属性值(再次解释:这里获取的具体的这个属性的值是怎么来的呢?比如颜色和宽度,这个在attr.xml中定义了相关的名字,而在使用RoundImageView的xml布局文件中,我们会为其设置值,这里需要用的值,就是从那里设置的),并设置在本控件中,然后继承onDraw方法,画出自己想要的图形或者形状即可。

由于我在代码中加了很多注释,我就直接给大家介绍代码了哈。





第一步:定义RoundImageView的属性配置文件:attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources> <declare-styleable name="round_image_view">
<attr name="border_width" format="dimension" />
<attr name="border_incolor" format="color" />
<attr name="border_outcolor" format="color"></attr>
</declare-styleable> </resources>

第二步:自定义圆形控件RoundImageView并继承ImageView

package net.loonggg.rivd.demo.view;

import net.loonggg.rivd.demo.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.util.AttributeSet;
import android.widget.ImageView; /**
*
* @author loongggdroid
*
*/
public class RoundImageView extends ImageView {
private int mBorderThickness = 0;
private Context mContext;
private int defaultColor = 0xFFFFFFFF;
// 外圆边框颜色
private int mBorderOutsideColor = 0;
// 内圆边框颜色
private int mBorderInsideColor = 0;
// RoundImageView控件默认的长、宽
private int defaultWidth = 0;
private int defaultHeight = 0; public RoundImageView(Context context) {
super(context);
mContext = context;
} public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
// 设置RoundImageView的属性值,比如颜色,宽度等
setRoundImageViewAttributes(attrs);
} public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
setRoundImageViewAttributes(attrs);
} // 从attr.xml文件中获取属性值,并给RoundImageView设置
private void setRoundImageViewAttributes(AttributeSet attrs) {
TypedArray a = mContext.obtainStyledAttributes(attrs,
R.styleable.round_image_view);
mBorderThickness = a.getDimensionPixelSize(
R.styleable.round_image_view_border_width, 0);
mBorderOutsideColor = a.getColor(
R.styleable.round_image_view_border_outcolor, defaultColor);
mBorderInsideColor = a.getColor(
R.styleable.round_image_view_border_incolor, defaultColor);
a.recycle();
} // 具体解释:比如我自定义一个控件,怎么实现呢,以RoundImageView为例,首先是继承ImageView,然后实现其构造函数,在构造函数中,获取attr中的属性值(再次解释:这里获取的具体的这个属性的值是怎么来的呢?比如颜色和宽度,这个在attr.xml中定义了相关的名字,而在使用RoundImageView的xml布局文件中,我们会设置其值,这里需要用的值,就是从那里设置的),并设置在本控件中,然后继承onDraw方法,画出自己想要的图形或者形状即可
/**
* 这个是继承的父类的onDraw方法
*
* onDraw和下面的方法不用管,基本和学习自定义没关系,就是实现怎么画圆的,你可以改变下面代码试着画三角形头像,哈哈
*/
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
this.measure(0, 0);
if (drawable.getClass() == NinePatchDrawable.class)
return;
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
if (defaultWidth == 0) {
defaultWidth = getWidth();
}
if (defaultHeight == 0) {
defaultHeight = getHeight();
}
int radius = 0;
// 这里的判断是如果内圆和外圆设置的颜色值不为空且不是默认颜色,就定义画两个圆框,分别为内圆和外圆边框
if (mBorderInsideColor != defaultColor
&& mBorderOutsideColor != defaultColor) {
radius = (defaultWidth < defaultHeight ? defaultWidth
: defaultHeight) / 2 - 2 * mBorderThickness;
// 画内圆
drawCircleBorder(canvas, radius + mBorderThickness / 2,
mBorderInsideColor);
// 画外圆
drawCircleBorder(canvas, radius + mBorderThickness
+ mBorderThickness / 2, mBorderOutsideColor);
} else if (mBorderInsideColor != defaultColor
&& mBorderOutsideColor == defaultColor) {// 这里的是如果内圆边框不为空且颜色值不是默认值,就画一个内圆的边框
radius = (defaultWidth < defaultHeight ? defaultWidth
: defaultHeight) / 2 - mBorderThickness;
drawCircleBorder(canvas, radius + mBorderThickness / 2,
mBorderInsideColor);
} else if (mBorderInsideColor == defaultColor
&& mBorderOutsideColor != defaultColor) {// 这里的是如果外圆边框不为空且颜色值不是默认值,就画一个外圆的边框
radius = (defaultWidth < defaultHeight ? defaultWidth
: defaultHeight) / 2 - mBorderThickness;
drawCircleBorder(canvas, radius + mBorderThickness / 2,
mBorderOutsideColor);
} else {// 这种情况是没有设置属性颜色的情况下,即没有边框的情况
radius = (defaultWidth < defaultHeight ? defaultWidth
: defaultHeight) / 2;
}
Bitmap roundBitmap = getCroppedRoundBitmap(bitmap, radius);
canvas.drawBitmap(roundBitmap, defaultWidth / 2 - radius, defaultHeight
/ 2 - radius, null);
} /**
* 获取裁剪后的圆形图片
*
* @param bmp
* @param radius
* 半径
* @return
*/
public Bitmap getCroppedRoundBitmap(Bitmap bmp, int radius) {
Bitmap scaledSrcBmp;
int diameter = radius * 2;
// 为了防止宽高不相等,造成圆形图片变形,因此截取长方形中处于中间位置最大的正方形图片
int bmpWidth = bmp.getWidth();
int bmpHeight = bmp.getHeight();
int squareWidth = 0, squareHeight = 0;
int x = 0, y = 0;
Bitmap squareBitmap;
if (bmpHeight > bmpWidth) {// 高大于宽
squareWidth = squareHeight = bmpWidth;
x = 0;
y = (bmpHeight - bmpWidth) / 2;
// 截取正方形图片
squareBitmap = Bitmap.createBitmap(bmp, x, y, squareWidth,
squareHeight);
} else if (bmpHeight < bmpWidth) {// 宽大于高
squareWidth = squareHeight = bmpHeight;
x = (bmpWidth - bmpHeight) / 2;
y = 0;
squareBitmap = Bitmap.createBitmap(bmp, x, y, squareWidth,
squareHeight);
} else {
squareBitmap = bmp;
}
if (squareBitmap.getWidth() != diameter
|| squareBitmap.getHeight() != diameter) {
scaledSrcBmp = Bitmap.createScaledBitmap(squareBitmap, diameter,
diameter, true);
} else {
scaledSrcBmp = squareBitmap;
}
Bitmap output = Bitmap.createBitmap(scaledSrcBmp.getWidth(),
scaledSrcBmp.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output); Paint paint = new Paint();
Rect rect = new Rect(0, 0, scaledSrcBmp.getWidth(),
scaledSrcBmp.getHeight()); paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawCircle(scaledSrcBmp.getWidth() / 2,
scaledSrcBmp.getHeight() / 2, scaledSrcBmp.getWidth() / 2,
paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(scaledSrcBmp, rect, rect, paint);
bmp = null;
squareBitmap = null;
scaledSrcBmp = null;
return output;
} /**
* 画边缘的圆,即内圆或者外圆
*/
private void drawCircleBorder(Canvas canvas, int radius, int color) {
Paint paint = new Paint();
/* 去锯齿 */
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setColor(color);
/* 设置paint的 style 为STROKE:空心 */
paint.setStyle(Paint.Style.STROKE);
/* 设置paint的外框宽度 */
paint.setStrokeWidth(mBorderThickness);
canvas.drawCircle(defaultWidth / 2, defaultHeight / 2, radius, paint);
}
}

第三步:在xml配置中使用控件:activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:loonggg="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingTop="20dp" > <!-- 没有指定圆形ImageView属性时,默认没有外边圆颜色 --> <net.loonggg.rivd.demo.view.RoundImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/pigu" /> <!-- border_outcolor 外部圆圈的颜色 -->
<!-- border_incolor 内部部圆圈的颜色 -->
<!-- border_width 外圆和内圆的宽度 -->
<!-- 再解释一遍,我们在布局中使用了我们在sttr中定义的属性,并在这里的布局文件中赋了值,所以在RoundImageView类中的结构体设置属性使用的值,就是我们在这里赋的,如果不使用attr.xml文件也可以,这样就是我们在activity中使用这个控件的时候,再设置值,不如这样方便罢了,比如昨天我们讲的【自定义带图片和文字的ImageTextButton】那样罢了 --> <!-- 说明:这里的loonggg可能大家不太明白,这个名字可以随便起,你们也可以自己随便定义,只要上下统一即可,在布局声明的时候一样就行,比如我在布局顶端是这样声明的 xmlns:loonggg="http://schemas.android.com/apk/res-auto" --> <net.loonggg.rivd.demo.view.RoundImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="20dp"
android:src="@drawable/pigu"
loonggg:border_incolor="#000fff"
loonggg:border_outcolor="#fff000"
loonggg:border_width="10dp" /> </LinearLayout>

废话不多说了,直接上demo,获取demo的方法跟以前一样,只需在公众号里回复关键字“3”即可获得。

微信公众号:smart_android ,公众号[非著名程序员]可能是东半球最好的技术分享公众号。每天,每周定时推送一些有关移动开发的原创文章和教程。

自定义圆形控件RoundImageView并认识一下attr.xml的更多相关文章

  1. 自定义圆形控件RoundImageView并认识一下attr

    昨天我们学习了自定义带图片和文字的ImageTextButton,非常简单,我承诺给大家要讲一下用自定义属性的方式学习真正的实现自定义控件,在布局文件中使用属性的方式就需要用到attr.xml这个文件 ...

  2. 自定义圆形控件 RoundImageView

    1.自定义圆形控件 RoundImageView package com.ronye.CustomView; import android.content.Context; import androi ...

  3. CircleImageView自定义圆形控件的使用

    1.自定义圆形控件github地址: https://github.com/hdodenhof/CircleImageView 主要的类: package de.hdodenhof.circleima ...

  4. Android开发(二)——自定义圆形控件的使用CircleImageView

    CircleImageView,a fast circular ImageView perfect for profile images. 主要的类CircleImageView: package d ...

  5. 【Android开源】CircleImageView自定义圆形控件的使用

    github地址:https://github.com/hdodenhof/CircleImageView package de.hdodenhof.circleimageview; import e ...

  6. Android - 自定义控件之圆形控件

    自定义控件 - 圈圈 Android L: Android Studio 效果:能够自定义圆圈半径和位置:设定点击效果:改变背景颜色 下面是demo图 点击前: 点击后: 自定义控件一般要继承View ...

  7. 安卓自定义组合控件--toolbar

    最近在学习安卓APP的开发,用到了toolbar这个控件, 最开始使用时include layout这种方法,不过感觉封装性不好,就又改成了自定义组合控件的方式. 使用的工具为android stud ...

  8. Android自定义控件之自定义组合控件

    前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...

  9. asp.net webform 自定义分页控件

    做web开发一直用到分页控件,自己也动手实现了个,使用用户自定义控件. 翻页后数据加载使用委托,将具体实现放在在使用分页控件的页面进行注册. 有图有真相,给个直观的认识: 自定义分页控件前台代码: & ...

随机推荐

  1. pom.xml 样例

    <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven ...

  2. WebApi深入学习--概述+路由查找

    如何创建Controller这里就不说了,只写一些可能是高阶知识的内容 关于WebApi的官方介绍及示例 http://www.asp.net/web-api/ 1.跨域 Asp.NET有专门的跨域扩 ...

  3. DateTime , DateTime2 ,DateTimeOffset 之间的小区别

    闲来无事列了个表比对一下这3兄弟之间还是有一点差距的╮(╯_╰)╭   DateTime DateTime2 DateTimeOffset 日期范围 1753-01-01到 9999-12-31 00 ...

  4. Web环境使用相对路径发布Webservice

    常我们的Webservice服务的发布地址都将是一个相对路径,在与Spring一起使用时我们需要引入Cxf配置Webservice的schema,如jaxws,用以定义对应的Webservice. & ...

  5. HQL查询语句

    查询语言 Hibernate 查询语言(HQL)是一种面向对象的查询语言,类似于 SQL,但不是去对表和列进行操作,而是面向对象和它们的属性. HQL 查询被 Hibernate 翻译为传统的 SQL ...

  6. DataTable操作

    一 复制DataTable中符合条件的DataRow到新的DataTable中 One: DataTable TableTemp = new DataTable();//临时table DataTab ...

  7. UDT中的epoll

    epoll 是为处理大量句柄而改进的poll,在UDT中也有支持.UDT使用了内核提供的epoll,主要是epoll_create,epoll_wait,epoll_ctl,UDT定义了CEPollD ...

  8. GacUI学习(二)

    GacUI学习(一)之高仿系统记事本(二) 转载请注明来源:http://www.cnblogs.com/lyfh/p/6107614.html 上篇<GacUI学习(一)之高仿系统记事本(一) ...

  9. js 读取 cookie

    (新摘未验证)// 将document.cookie的值以名/值对组成的一个对象返回 // 假设储存cookie的值的时候是采用encodeURIComponent()函数编码的 function g ...

  10. POJ 1741 Tree (树的点分治入门)

      Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 16172   Accepted: 5272 Descripti ...