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

昨天我们学习了自定义带图片和文字的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>

时间: 2024-11-10 14:40:40

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

自定义圆形控件 RoundImageView

1.自定义圆形控件 RoundImageView package com.ronye.CustomView; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Porte

android开源系列:CircleImageView自定义圆形控件的使用

1.自定义圆形控件github地址:https://github.com/hdodenhof/CircleImageView 主要的类: package de.hdodenhof.circleimageview; import edu.njupt.zhb.main.R; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import andr

CircleImageView自定义圆形控件的使用

1.自定义圆形控件github地址: https://github.com/hdodenhof/CircleImageView 主要的类: package de.hdodenhof.circleimageview; import edu.njupt.zhb.main.R; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import and

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

github地址:https://github.com/hdodenhof/CircleImageView package de.hdodenhof.circleimageview; import edu.njupt.zhb.main.R; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Bi

Android自定义控件之自定义组合控件(三)

前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发成本,以及维护成本. 使用自定义组合控件的好处? 我们在项目开发中经常会遇见很多相似或者相同的布局,比如APP的标题栏,我们从三种方式实现标题栏来对比自定义组件带来的好处,毕竟好的东西还是以提高开发效率,降低开发成本为导向的. 1.)第一种方式:直接在每个xml布局中写相同的标题栏布局代码 <?xm

自定义组合控件和在自定义控件中使用自定义属性

今天,整理了一下我平时的笔记,写一个比较简单的自定义组合控件,仅供小白参考,大神请绕道,希望能够对大家有一些帮助 首先,得明白为什么我们需要自定义组合控件,它是因为原有控件并不能满足开发的需求,或者说并不能达到我们想要的一种效果,这个时候,就需要我们自己定义一些控件,以达到目的 ![先来看一下效果](http://img.blog.csdn.net/20160716224219109) 个人总结自定义控件的步骤: 1.先写一个布局,这里我用的是一个相对布局,我这里的相对布局就是根布局了 <?xm

自定义HtmlHelper控件

在asp.net mvc 中每一个Html控件都返回了MvcHtmlString ,他继承了HtmlString.下面自定义一个关于显示男女性别的自定义Html控件,使在创建页面时,可以直接调用该自定义的Html控件.可以查看其他的Html控件返回的是HtmlHelper,所以自定义的时候也要返回相同的类型直接在Controls文件夹下建立要自定义的html控件代码如下: using System.Web.Mvc; using System.Text; namespace System.Web.

【转】带checkbox的ListView实现(二)——自定义Checkable控件的实现方法

原文网址:http://blog.csdn.net/harvic880925/article/details/40475367 前言:前一篇文章给大家展示了传统的Listview的写法,但有的时候我们并不想在DataHolder类中加一个标识是否选中的checked的成员变量,因为在项目开发中,大部分的ListItemLayout布局都是大家共用的,有些人根本不需要checkbox控件,所以会在初始化的时候把这个控件给隐藏掉,但我们的DataHolder在构造的时候以及ListItemAdapt

Android自定义组合控件--底部多按钮切换

效果图: 现在市场上大多数软件都是类似于上面的结构,底部有几个按钮用于切换到不同的界面.基于OOP思想,我想把下面的一整块布局封装成一个类,也就是我们的自定义组合控件-底部多按钮切换布局,我把它叫做BottomLayout 看上面的布局,几个按钮横向排列,我们先看一下布局 最外面LinearLayout 方向 horizontal,然后5个weight相同的RelativeLayout,每个RelativeLayout里面有一个Button(用了显示选中状态)个ImageView(用来显示红点)