【Android】Android自定义带board的圆角控件

介绍

圆角控件常用于头像,按钮,图标等,用途十分广泛,而且常常配合board使用。

在IOS中,UIVIew的CALayer层已经提供了圆角和board的方法,所以圆角控件的制作非常简单,只需要类似以下简单代码即可实现:

    view.layer.cornerRadius = 20;
    view.layer.borderColor = [UIColor yellowColor].CGColor;
    view.layer.borderWidth = 10;
    view.clipsToBounds = YES;

而在Android中,系统并没有提供这么直接的方式,所以想要实现同样的效果需要费点心了。本文将会介绍一种在Android中实现带board属性的圆角控件的方法。该方法定义了一个RoundImageView重写了ImageView的onDraw方法,并加入了一些自定义的属性,最后实现以上同样效果的代码非常简洁:

    <com.me.obo.circleboardimage.circleview.RoundImageView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/head"
        attr:border_width="3dp"
        attr:corner_y="40dp"
        attr:corner_x="40dp"
        attr:border_color="#FFFFFF"/>

下面就介绍如何实现这样一个RoundImageView

遮罩

在Android中,遮罩功能非常强大,可以用于生成两张图片相互截取的结果。

具体参数和遮罩的效果可以见链接:Android 实现遮罩

在RoundImageView中,遮罩用于清除控件外圈的内容,从而获取到圆角的效果。这里的思路是先获取到控件本身所绘制的图片,之后获取圆角矩形遮罩图片,然后两个图片采用DST_IN遮罩模式来截取中间的遮罩效果,即:

代码实现如下:

        // 获取imageview原先的图片
        super.onDraw(mDestCanvas);

        // 创建矩形,表示圆角矩形
        if (mRoundRectClip == null) {
            mRoundRectClip = new RectF(mBorderValue, mBorderValue, getWidth() - mBorderValue, getHeight() - mBorderValue);
        }
        // 绘制圆角矩形
        mSrcCanvas.drawRoundRect(mRoundRectClip,mCornerXValue,mCornerYValue,mNomalPaint);

        // 使用遮罩画笔扣除原图中的圆角矩形外面的部分
        mDestCanvas.drawBitmap(mSrcBitmap,0,0,mPaintClip);

在获取到遮罩处理的图片之后,为其添加board将会变得容易,也就是在外圈绘制出一个带有宽度的圆即可。

代码实现如下:

        // 创建board的矩形
        if (mRoundRectBorder == null) {
            mRoundRectBorder = new RectF(mBorderValue / 2, mBorderValue / 2, getWidth() - mBorderValue / 2, getHeight() - mBorderValue / 2);
        }
        // 绘制board
        mDestCanvas.drawRoundRect(mRoundRectBorder, mCornerXValue, mCornerYValue, mPaintBoard);

整个RoundImageView完整的代码如下:

package com.me.obo.circleboardimage.circleview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.me.obo.circleboardimage.R;

/**
 * Created by obo on 16/5/11.
 * Email:[email protected]
 * Git:https://github.com/OboBear
 * Blog:http://blog.csdn.net/leilba
 */
public class RoundImageView extends ImageView {

    private float mCornerXValue ;
    private float mCornerYValue ;
    private float mBorderValue ;
    private int mBorderColor ;

    public RoundImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 获取自定义参数
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.RoundImageView);
        // board颜色
        mBorderColor = typedArray.getColor(R.styleable.RoundImageView_border_color,Color.argb(0,0,0,0));
        // 获取X方向曲率
        mCornerXValue = typedArray.getDimension(R.styleable.RoundImageView_corner_x,0);
        // 获取Y方向曲率
        mCornerYValue = typedArray.getDimension(R.styleable.RoundImageView_corner_y,0);
        // board宽
        mBorderValue = typedArray.getDimension(R.styleable.RoundImageView_border_width,0);
        // 用完需要recycle
        typedArray.recycle();

        initPaints();
    }

    private void initPaints() {
        // 创建普通画笔
        if (mNomalPaint == null) {
            mNomalPaint = new Paint();
        }

        // 创建遮罩画笔
        if (mPaintClip == null) {
            mPaintClip = new Paint();
            mPaintClip.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            mPaintClip.setAntiAlias(true);
        }

        // 创建board的画笔
        if (mPaintBoard == null) {
            mPaintBoard = new Paint();
            mPaintBoard.setColor(mBorderColor);
            mPaintBoard.setStyle(Paint.Style.STROKE);
            mPaintBoard.setStrokeWidth(mBorderValue);
        }
    }

    Bitmap mDestBitmap;
    Bitmap mSrcBitmap;
    Canvas mDestCanvas;
    Canvas mSrcCanvas;
    Paint mPaintClip;
    Paint mNomalPaint;
    Paint mPaintBoard;
    RectF mRoundRectClip;
    RectF mRoundRectBorder;

    @Override
    protected void onDraw(Canvas canvas) {
        // 创建遮罩图片和画布
        if (mDestBitmap == null) {
            mDestBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
            mSrcBitmap = Bitmap.createBitmap(getWidth(),getHeight(), Bitmap.Config.ARGB_8888);
            mDestCanvas = new Canvas(mDestBitmap);
            mSrcCanvas = new Canvas(mSrcBitmap);
        }
        // 获取imageview原先的图片
        super.onDraw(mDestCanvas);

        // 创建矩形,表示圆角矩形
        if (mRoundRectClip == null) {
            mRoundRectClip = new RectF(mBorderValue, mBorderValue, getWidth() - mBorderValue, getHeight() - mBorderValue);
        }
        // 绘制圆角矩形
        mSrcCanvas.drawRoundRect(mRoundRectClip,mCornerXValue,mCornerYValue,mNomalPaint);

        // 使用遮罩画笔扣除原图中的圆角矩形外面的部分
        mDestCanvas.drawBitmap(mSrcBitmap,0,0,mPaintClip);

        // 创建board的矩形
        if (mRoundRectBorder == null) {
            mRoundRectBorder = new RectF(mBorderValue / 2, mBorderValue / 2, getWidth() - mBorderValue / 2, getHeight() - mBorderValue / 2);
        }
        // 绘制board
        mDestCanvas.drawRoundRect(mRoundRectBorder, mCornerXValue, mCornerYValue, mPaintBoard);

        // 绘制最终的圆角带有board的图
        canvas.drawBitmap(mDestBitmap,0,0,mNomalPaint);
    }

}

自定义Attribute

可能有人要问,圆角弯曲度和board的参数是如何传递到RoundImageView里的。实际上,这里采用了自定义Attribute的方式,该操作需要到res/values 目录下创建 attr.xml 文件,在里面写上自定义的参数名称以及类型:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundImageView">
        <attr name="border_width" format="dimension"/>
        <attr name="border_color" format="color"/>
        <attr name="corner_x" format="dimension"/>
        <attr name="corner_y" format="dimension"/>
    </declare-styleable>
</resources>

有了这个,就可以在RoundImageView的构造方法里面,获取到自定义attri的值了

    public RoundImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 获取自定义参数
        TypedArray typedArray = context.obtainStyledAttributes(attrs,
                R.styleable.RoundImageView);
        // board颜色
        mBorderColor = typedArray.getColor(R.styleable.RoundImageView_border_color,Color.argb(0,0,0,0));
        // 获取X方向曲率
        mCornerXValue = typedArray.getDimension(R.styleable.RoundImageView_corner_x,0);
        // 获取Y方向曲率
        mCornerYValue = typedArray.getDimension(R.styleable.RoundImageView_corner_y,0);
        // board宽
        mBorderValue = typedArray.getDimension(R.styleable.RoundImageView_border_width,0);
        // 用完需要recycle
        typedArray.recycle();

        initPaints();
    }

在layout里使用的时候,需要在layout的xml开头里面申请自定义的参数即可

xmlns:attr="http://schemas.android.com/apk/res-auto"

最后,在layout里面调用RoundImageView的代码非常简洁:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:attr="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/darker_gray"
    android:orientation="vertical">

    <com.me.obo.circleboardimage.circleview.RoundImageView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/head"
        attr:border_width="3dp"
        attr:corner_y="40dp"
        attr:corner_x="40dp"
        attr:border_color="#FFFFFF"/>

    <com.me.obo.circleboardimage.circleview.RoundImageView
        android:layout_width="180dp"
        android:layout_height="180dp"
        android:src="@drawable/head"
        attr:border_width="2dp"
        attr:corner_y="40dp"
        attr:corner_x="40dp"
        attr:border_color="#FF0000"
        android:scaleType="fitXY"/>

</LinearLayout>

效果如下:

资源下载

RoundImageView

时间: 2024-10-15 00:35:19

【Android】Android自定义带board的圆角控件的相关文章

wpf自定义带刻度的柱状图控件

效果图: 主要代码xaml: <UserControl x:Class="INSControls._01Conning.Steer.ConningSpeedBar" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="htt

【安卓笔记】带自定义属性的view控件

开发中经常需要自定义view控件或者组合控件,某些控件可能需要一些额外的配置.比如自定义一个标题栏,你可能需要根据不同尺寸的手机定制不同长度的标题栏,或者更常见的你需要配置标题栏的背景,这时候,你就会考虑到你写的view的扩展性问题,通常情况下,我们可以为这个自定义的标题栏加上一些setXXX方法,供外界调用,设置其颜色.长度等属性.但是我们都知道,在使用系统控件时,我们大多数情况下并不需要在代码中配置控件,而仅仅只需在布局文件中对控件宽.高.颜色等进行配置,这样做的好处就将UI与业务逻辑解耦,

【Android】Android实现自定义带文字和图片的Button

在Android开发中经常会需要用到带文字和图片的button,下面来讲解一下常用的实现办法. 一.用系统自带的Button实现 最简单的一种办法就是利用系统自带的Button来实现,这种方式代码量最小.在Button的属性中有一个是drawableLeft,这个属性可以把图片设置在文字的左边,但是这种方式必须让icon的背景色是透明的,如果icon的背景色不是透明的话,会导致点击按钮时icon部分的背景色不会发生变化. 主要代码: <Button android:id="@+id/bt3

Android 自定义View之自绘控件

首先要提前声明一下,我对于自定义View的理解并不是很深,最近啃了几天guolin博主写的关于自定义View的博客,讲的非常棒,只不过涉及到源码和底层的一些东西,我自己就懵逼了,目前只是会了关于自定义View的简单使用,不过还是要写出来,当做练习了,哈哈~对于一些没有接触过的初学者,希望会有所帮助,共同成长: 按类型,自定义View可以分为三种:自绘控件.组合控件.继承控件,对于这三种类型,我会写三篇博客来分别介绍和使用. 自定义View中有三个非常重要的方法,分别为: onMeasure():

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

不少人应该见过小米手机系统音量控制UI,一个圆形带动画效果的音量加减UI,效果很好看.它是怎么实现的呢?这篇博客来揭开它的神秘面纱.先上效果图 相信很多人都知道Android自定义控件的三种方式,Android自定义控件View(一)自绘控件,Android自定义控件View(二)继承控件,还有就是这一节即将学习到的组合控件.我们通过实现圆形音量UI来讲解组合控件的定义和使用. 组合控件 所谓组合控件就是有多个已有的控件组合而成一个复杂的控件.比如上图的音量控件就是一个完美的组合控件.我们来分析

Android自定义控件 ----- 基本绘制流程,简单控件的实现

一.自定义控件(一) --- 自定义属性TextView 1,定义属性,制作attrs.xml文件: 属性值: string,color,attr,array,bool,declare-styleable,dimen,drawable,eat-comment,fraction, integer,integer-array,item,plurals,string-array,style 属性取值范围: string,color,demension,integer,enum,reference,fl

android在代码中四种设置控件背景颜色的方法(包括RGB)

转载请注明出处: http://blog.csdn.net/fth826595345/article/details/9208771  TextView tText=(TextView) findViewById(R.id.textv_name); //第1种: tText.setTextColor(android.graphics.Color.RED);//系统自带的颜色类 // 第2种: tText.setTextColor(0xffff00ff);//0xffff00ff是int类型的数据

Android scrollview 上滑固定某一控件(美团团购详情UI)完美版

在scrollview 上滑固定某一控件(美团团购详情UI)文中介绍了怎么用touchlistener实现类似上滑停住的效果,但是这种方法存在一个明显的bug,就是在内容比较多的时候, 大部分人都是以滑动方式查看内容,而不是touch的方式,这就会导致最上面的滑块出现不及时,或者延后的现象,这里介绍一个全新的方法去实现类似效果,可以很好的解决以上问题. 目前在scrollview中没有onscrolllistener所以需要自己去实现,先复写一个scrollview: package com.e

android快速上手(三)常用控件使用

完成了android的第一个程序HelloWorld,下面就开始控件的学习,下面是一些常见的控件. (一)TextView 简单的文本描述 (二)EditText 编辑框,输入文字信息 (三)Button 按钮,点击后会触发点击事件,可以对事件进行处理 (四)ImageView 图片控件,可以加载图片显示 (五)ListView 列表,需要跟适配器Adapter结合,适配器提供数据 (六)Toast 闪现提示语,常用于普通的提示文本,只显示一小段时间自动消失 (七)ScrollView 一般用于