Android自定义控件之自定义属性(二)

 更新时间:2016年08月01日 09:28:03   作者:总李写代码  
这篇文章主要为大家详细介绍了Android自定义控件之自定义属性,如何给自定义控件自定义一些属性,感兴趣的小伙伴们可以参考一下

前言:
上篇介绍了自定义控件的基本要求以及绘制的基本原理,本篇文章主要介绍如何给自定义控件自定义一些属性。本篇文章将继续以上篇文章自定义圆形百分比为例进行讲解。有关原理知识请参考Android自定义控件基本原理详解(一)这篇文章。 

需求产生背景:
为何要引入自定义属性?当Android提供的原生属性不能满足实际的需求的时候,比如我们需要自定义圆形百分比半径大小、圆形背景、圆形显示的位置、圆形进度的背景等等。这个时候就需要我们自定义属性了。 

自定义属性步骤:
1.)在res/values文件下添加一个attrs.xml文件,如果项目比较大的话,会导致attrs.xml代码相当庞大,这时可以根据相应的功能模块起名字,方便查找,例如:登录模块相关attrs_login.xml 

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="RoundImageView">
  <attr name="borderRadius" />
  <attr name="type" />
 </declare-styleable>

</resources>

2.)如何声明一组属性 
使用<declare-styleable name="PercentView"></declare-styleable>来定义一个属性集合,name就是属性集合的名字,这个名字一定要起的见名知意。 

 <declare-styleable name="PercentView">
 <!--添加属性-->
 </declare-styleable> 

然后就是定义属性值了,通过<attr name="textColor" format="color" /> 方式定义属性值,属性名字同样也要起的见名知意,format表示这个属性的值的类型,类型有以下几种:
 •reference:引用资源
 •string:字符串
 •Color:颜色
 •boolean:布尔值
 •dimension:尺寸值
 •float:浮点型
 •integer:整型
 •fraction:百分数
 •enum:枚举类型
 •flag:位或运算 

基于上面的要求,我们可以定义一下百分比控件属性

 <declare-styleable name="PercentView">
  <attr name="percent_circle_gravity"><!--圆形绘制的位置-->
   <flag name="left" value="0" />
   <flag name="top" value="1" />
   <flag name="center" value="2" />
   <flag name="right" value="3" />
   <flag name="bottom" value="4" />
  </attr>
  <attr name="percent_circle_radius" format="dimension" /><!--圆形半径-->
  <attr name="percent_circle_progress" format="integer" /><!--当前进度值-->
  <attr name="percent_progress_color" format="color" /><!--进度显示颜色-->
  <attr name="percent_background_color" format="color" /><!--圆形背景色-->
 </declare-styleable>

3.)布局中如何使用 

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

 <com.whoislcj.views.PercentView
  android:layout_width="200dp"
  android:layout_height="200dp"
  android:layout_margin="10dp"
  android:background="@color/red"
  android:padding="10dp"
  lee:percent_background_color="@color/gray"
  lee:percent_circle_gravity="left"
  lee:percent_circle_progress="30"
  lee:percent_circle_radius="50dp"
  lee:percent_progress_color="@color/blue" />

</LinearLayout>

为属性集设置一个属性集名称,我这里用的lee,我这是因为实在想不起使用什么属性集名称了,建议在真正的项目中使用项目的缩写,比如微信可能就是使用wx。 

4.)自定义控件中如何获取自定义属性 
每一个属性集合编译之后都会对应一个styleable对象,通过styleable对象获取TypedArray typedArray,然后通过键值对获取属性值,这点有点类似SharedPreference的取法。 

 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PercentView);
 if (typedArray != null) {
  backgroundColor = typedArray.getColor(R.styleable.PercentView_percent_background_color, Color.GRAY);
  progressColor = typedArray.getColor(R.styleable.PercentView_percent_progress_color, Color.BLUE);
  radius = typedArray.getDimension(R.styleable.PercentView_percent_circle_radius, 0);
  progress = typedArray.getInt(R.styleable.PercentView_percent_circle_progress, 0);
  gravity = typedArray.getInt(R.styleable.PercentView_percent_circle_gravity, CENTER);
  typedArray.recycle();
  }

5.)完整示例 

public class PercentView extends View {
 private final static String TAG = PercentView.class.getSimpleName();
 private Paint mPaint;
 private int backgroundColor = Color.GRAY;
 private int progressColor = Color.BLUE;
 private float radius;
 private int progress;
 private float centerX = 0;
 private float centerY = 0;
 public static final int LEFT = 0;
 public static final int TOP = 1;
 public static final int CENTER = 2;
 public static final int RIGHT = 3;
 public static final int BOTTOM = 4;
 private int gravity = CENTER;
 private RectF rectF; //用于定义的圆弧的形状和大小的界限

 public PercentView(Context context) {
  super(context);
  init();
 }

 public PercentView(Context context, AttributeSet attrs) {
  super(context, attrs);
  initParams(context, attrs);
  init();
 }

 public PercentView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  initParams(context, attrs);
  init();
 }

 private void init() {
  mPaint = new Paint();
  mPaint.setAntiAlias(true);
  rectF = new RectF();
 }

 private void initParams(Context context, AttributeSet attrs) {
  mPaint = new Paint();
  mPaint.setAntiAlias(true);
  rectF = new RectF();
  TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PercentView);
  if (typedArray != null) {
   backgroundColor = typedArray.getColor(R.styleable.PercentView_percent_background_color, Color.GRAY);
   progressColor = typedArray.getColor(R.styleable.PercentView_percent_progress_color, Color.BLUE);
   radius = typedArray.getDimension(R.styleable.PercentView_percent_circle_radius, 0);
   progress = typedArray.getInt(R.styleable.PercentView_percent_circle_progress, 0);
   gravity = typedArray.getInt(R.styleable.PercentView_percent_circle_gravity, CENTER);
   typedArray.recycle();
  }
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  Log.e(TAG, "onMeasure--widthMode-->" + widthMode);
  switch (widthMode) {
   case MeasureSpec.EXACTLY://
    break;
   case MeasureSpec.AT_MOST:
    break;
   case MeasureSpec.UNSPECIFIED:
    break;
  }
  Log.e(TAG, "onMeasure--widthSize-->" + widthSize);
  Log.e(TAG, "onMeasure--heightMode-->" + heightMode);
  Log.e(TAG, "onMeasure--heightSize-->" + heightSize);
  int with = getWidth();
  int height = getHeight();
  Log.e(TAG, "onDraw---->" + with + "*" + height);
  centerX = with / 2;
  centerY = with / 2;
  switch (gravity) {
   case LEFT:
    centerX = radius + getPaddingLeft();
    break;
   case TOP:
    centerY = radius + getPaddingTop();
    break;
   case CENTER:
    break;
   case RIGHT:
    centerX = with - radius - getPaddingRight();
    break;
   case BOTTOM:
    centerY = height - radius - getPaddingBottom();
    break;
  }
  float left = centerX - radius;
  float top = centerY - radius;
  float right = centerX + radius;
  float bottom = centerY + radius;
  rectF.set(left, top, right, bottom);
 }

 @Override
 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  super.onLayout(changed, left, top, right, bottom);
  Log.e(TAG, "onLayout");
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  mPaint.setColor(backgroundColor);
  // FILL填充, STROKE描边,FILL_AND_STROKE填充和描边
  mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
  canvas.drawCircle(centerX, centerY, radius, mPaint);
  mPaint.setColor(progressColor);

  double percent = progress * 1.0 / 100;
  int angle = (int) (percent * 360);
  canvas.drawArc(rectF, 270, angle, true, mPaint); //根据进度画圆弧
 }
}

运行结果:
 根据不同的配置显示的两种效果

 

小结: 
通过自定义属性可以达到自定义的控件也能像原生的控件一样实现可配置。但是在实际的项目开发中,像本文介绍的这种自定义控件使用频率并不是最高的,使用频率较高的是通过自定义一个组合控件的方式,来达到布局文件的复用,以减少项目维护成本以及开发成本,下篇文章将重点介绍如何自定义控件组合,点击查看

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Android使用Service实现简单音乐播放实例

    Android使用Service实现简单音乐播放实例

    这篇文章主要为大家详细介绍了Android使用Service实现简单音乐播放实例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • 使用android studio开发工具编译GBK转换三方库iconv的方法

    使用android studio开发工具编译GBK转换三方库iconv的方法

    这篇文章主要介绍了使用android studio开发工具编译GBK转换三方库iconv的教程,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • Android实现加法计算器

    Android实现加法计算器

    这篇文章主要为大家详细介绍了Android实现加法计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • Android跳转到通讯录获取用户名称和手机号码的实现思路

    Android跳转到通讯录获取用户名称和手机号码的实现思路

    这篇文章主要介绍了Android跳转到通讯录获取用户名称和手机号码的实现思路,当用户点击跳转到通讯录界面 并取通讯录姓名和手机号码 ,实现代码简单易懂,非常不错感兴趣的朋友一起看看吧
    2016-10-10
  • Android开发中Eclipse报错及对应处理方法总结

    Android开发中Eclipse报错及对应处理方法总结

    这篇文章主要介绍了Android开发中Eclipse报错及对应处理方法,实例汇总了使用eclipse开发Android项目过程中常见的错误提示及对应的处理技巧,需要的朋友可以参考下
    2015-12-12
  • Android性能优化之图片大小,尺寸压缩综合解决方案

    Android性能优化之图片大小,尺寸压缩综合解决方案

    随着Android手机的越来越先进,给我们开发者而言传递的图片也是越来越大,这个时候我们可以对一些没有必要原图展示的图片进行压缩,这篇文章主要给大家介绍了关于Android性能优化之图片大小,尺寸压缩的综合解决方案,需要的朋友可以参考下
    2022-04-04
  • RecyclerView实现常见的列表菜单

    RecyclerView实现常见的列表菜单

    这篇文章主要为大家详细介绍了用RecyclerView实现移动应用中常见的列表菜单,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • android读取assets文件示例

    android读取assets文件示例

    这篇文章主要介绍了android读取assets文件示例,需要的朋友可以参考下
    2014-02-02
  • Android基于AccessibilityService制作的钉钉自动签到程序代码

    Android基于AccessibilityService制作的钉钉自动签到程序代码

    这篇文章主要介绍了Android基于AccessibilityService制作的钉钉自动签到程序代码,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • Android 双击Back键退出应用的实现方法

    Android 双击Back键退出应用的实现方法

    这篇文章主要介绍了Android 双击Back键退出应用的实现方法的相关资料,希望通过本文能帮助到大家,让大家实现这样的功能,需要的朋友可以参考下
    2017-10-10

最新评论