版本:1.0

日期:2014.3.21
版权:© 2013,2014 kince 转载注明出处
Setting应用下使用了不少自定义控件,比如这些效果:

流量显示
电量显示
存储空间显示
先介绍最后这个存储空间显示的LinearColorBar,通过名字就可以看出是是继承于LinearLayout,确实也是如此。分析一下这个效果,在控件的左边显示已经使用了多少空间,右边是所有可用空间。上面还有所显示的类别,RAM。当然最主要的还是那个环形的效果。看一下LinearColorBar的实现代码:
/**
*
*/
package com.example.settingscustomviewdemo.widget;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.LinearLayout;public class LinearColorBar extends LinearLayout {static final int LEFT_COLOR = 0xff0099cc;static final int MIDDLE_COLOR = 0xff0099cc;static final int RIGHT_COLOR = 0xff888888;private float mRedRatio;private float mYellowRatio;private float mGreenRatio;private boolean mShowingGreen;final Rect mRect = new Rect();final Paint mPaint = new Paint();int mLastInterestingLeft, mLastInterestingRight;int mLineWidth;final Path mColorPath = new Path();final Path mEdgePath = new Path();final Paint mColorGradientPaint = new Paint();final Paint mEdgeGradientPaint = new Paint();public LinearColorBar(Context context, AttributeSet attrs) {super(context, attrs);setWillNotDraw(false);mPaint.setStyle(Paint.Style.FILL);mColorGradientPaint.setStyle(Paint.Style.FILL);mColorGradientPaint.setAntiAlias(true);mEdgeGradientPaint.setStyle(Paint.Style.STROKE);mLineWidth = getResources().getDisplayMetrics().densityDpi >= DisplayMetrics.DENSITY_HIGH? 2 : 1;mEdgeGradientPaint.setStrokeWidth(mLineWidth);mEdgeGradientPaint.setAntiAlias(true);}public void setRatios(float red, float yellow, float green) {mRedRatio = red;mYellowRatio = yellow;mGreenRatio = green;invalidate();}public void setShowingGreen(boolean showingGreen) {if (mShowingGreen != showingGreen) {mShowingGreen = showingGreen;updateIndicator();invalidate();}}private void updateIndicator() {int off = getPaddingTop() - getPaddingBottom();if (off < 0) off = 0;mRect.top = off;mRect.bottom = getHeight();if (mShowingGreen) {mColorGradientPaint.setShader(new LinearGradient(0, 0, 0, off-2, RIGHT_COLOR&0xffffff, RIGHT_COLOR, Shader.TileMode.CLAMP));} else {mColorGradientPaint.setShader(new LinearGradient(0, 0, 0, off-2, MIDDLE_COLOR&0xffffff, MIDDLE_COLOR, Shader.TileMode.CLAMP));}mEdgeGradientPaint.setShader(new LinearGradient(0, 0, 0, off/2, 0x00a0a0a0, 0xffa0a0a0, Shader.TileMode.CLAMP));}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);updateIndicator();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int width = getWidth();int left = 0;int right = left + (int)(width*mRedRatio);int right2 = right + (int)(width*mYellowRatio);int right3 = right2 + (int)(width*mGreenRatio);int indicatorLeft, indicatorRight;if (mShowingGreen) {indicatorLeft = right2;indicatorRight = right3;} else {indicatorLeft = right;indicatorRight = right2;}if (mLastInterestingLeft != indicatorLeft || mLastInterestingRight != indicatorRight) {mColorPath.reset();mEdgePath.reset();if (indicatorLeft < indicatorRight) {final int midTopY = mRect.top;final int midBottomY = 0;final int xoff = 2;mColorPath.moveTo(indicatorLeft, mRect.top);mColorPath.cubicTo(indicatorLeft, midBottomY,-xoff, midTopY,-xoff, 0);mColorPath.lineTo(width+xoff-1, 0);mColorPath.cubicTo(width+xoff-1, midTopY,indicatorRight, midBottomY,indicatorRight, mRect.top);mColorPath.close();final float lineOffset = mLineWidth+.5f;mEdgePath.moveTo(-xoff+lineOffset, 0);mEdgePath.cubicTo(-xoff+lineOffset, midTopY,indicatorLeft+lineOffset, midBottomY,indicatorLeft+lineOffset, mRect.top);mEdgePath.moveTo(width+xoff-1-lineOffset, 0);mEdgePath.cubicTo(width+xoff-1-lineOffset, midTopY,indicatorRight-lineOffset, midBottomY,indicatorRight-lineOffset, mRect.top);}mLastInterestingLeft = indicatorLeft;mLastInterestingRight = indicatorRight;}if (!mEdgePath.isEmpty()) {canvas.drawPath(mEdgePath, mEdgeGradientPaint);canvas.drawPath(mColorPath, mColorGradientPaint);}if (left < right) {mRect.left = left;mRect.right = right;mPaint.setColor(LEFT_COLOR);canvas.drawRect(mRect, mPaint);width -= (right-left);left = right;}right = right2;if (left < right) {mRect.left = left;mRect.right = right;mPaint.setColor(MIDDLE_COLOR);canvas.drawRect(mRect, mPaint);width -= (right-left);left = right;}right = left + width;if (left < right) {mRect.left = left;mRect.right = right;mPaint.setColor(RIGHT_COLOR);canvas.drawRect(mRect, mPaint);}}
}

读完源码看一下它的变量,画笔Paint不说了,用于设置笔触的样式。除此之外就是Rect和Path了,关于这两个类的功能,其实从字面意思大体可以猜得出来。Rect是用于绘制矩形的,Path则用于画线,包括直线、二次曲线、三次曲线等。那从这两个类的用途就不难猜出它们各自在LinaerColorBar中的作用了,Rect用于绘制使用了多少空间的进度条,Path则是用于绘制那个二次型图案。
然后直接进入Draw()方法,开始初始化一些变量,这些变量之后会使用到。
          int width = getWidth();//获取组件宽度int left = 0;//int right = left + (int) (width * mRedRatio);//int right2 = right + (int) (width * mYellowRatio);//int right3 = right2 + (int) (width * mGreenRatio);//int indicatorLeft, indicatorRight;if (mShowingGreen) {indicatorLeft = right2;indicatorRight = right3;} else {indicatorLeft = right;indicatorRight = right2;}

这几个right值就是根据设置的空间使用大小转换而来的,其实就是控件宽度的比例值,在画Rect的时候传入即可。接着往下看,
                    mColorPath.moveTo(indicatorLeft, mRect.top);mColorPath.cubicTo(indicatorLeft, midBottomY, -xoff, midTopY,-xoff, 0);mColorPath.lineTo(width + xoff - 1, 0);mColorPath.cubicTo(width + xoff - 1, midTopY, indicatorRight,midBottomY, indicatorRight, mRect.top);mColorPath.close();

这段代码就是用于画这个弧形的,首先moveTo()方法,将画笔移动到这个点,然后使用cubicTo方法画一个二次曲线,因为画笔设置了Paint.Style.FILL,所以看起来像是一片的效果,而不是直线。
                    final float lineOffset = mLineWidth + .5f;mEdgePath.moveTo(-xoff + lineOffset, 0);mEdgePath.cubicTo(-xoff + lineOffset, midTopY, indicatorLeft+ lineOffset, midBottomY, indicatorLeft + lineOffset,mRect.top);mEdgePath.moveTo(width + xoff - 1 - lineOffset, 0);mEdgePath.cubicTo(width + xoff - 1 - lineOffset, midTopY,indicatorRight - lineOffset, midBottomY, indicatorRight- lineOffset, mRect.top);

这段代码用于在之前的基础上描边,
这样,弧形效果就实现了。然后就是下面的矩形了,
if (left < right) {mRect.left = left;mRect.right = right;mPaint.setColor(LEFT_COLOR);canvas.drawRect(mRect, mPaint);width -= (right - left);left = right;}right = right2;if (left < right) {mRect.left = left;mRect.right = right;mPaint.setColor(MIDDLE_COLOR);canvas.drawRect(mRect, mPaint);width -= (right - left);left = right;}right = left + width;if (left < right) {mRect.left = left;mRect.right = right;mPaint.setColor(RIGHT_COLOR);canvas.drawRect(mRect, mPaint);}

这个就相对简单了,用Rect直接画就行了。
总结:这个自定义的控件是继承于系统原有的容器控件LinearLayout,为什么要选择LinearLayout呢,其实也可以是RelativeLayout,容器控件都可以,只要把那三个TextView安放好位置就行。然后就是绘图了,这里结合了Paint、Path、Rect以及Canvas的使用,其实自定义控件很多时候就是使用这几个类,所以对这几个类的掌握尤为重要。那最后就是逻辑,这也是很重要的一个部分,对于效果我们可能想到使用什么类去实现,那对于效果的控制与变化就需要依靠逻辑了。
demo下载

Setting下的自定义控件LinearColorBar相关推荐

  1. 3.1-3.31推荐文章汇总

    3.1-3.31推荐文章汇总 [Eclipse AST]AST的创建   刘伟 Android WebKit HTML主资源加载过程   谭海燕 HTML5物理游戏开发 - 越野山地自行车(一)建立各 ...

  2. java settings文件夹_windows下打开.m2文件夹,没有找到setting.xml

    Frank作家 2018-03-15 10:07 已采纳 那就自己创建一个 手动创建本地仓库的存放路径,例如:D:\Java\m2\repository: 在windows的环境变量中增加了新的用户变 ...

  3. java m2文件放哪里_windows下打开.m2文件夹,没有找到setting.xml

    那就自己创建一个 手动创建本地仓库的存放路径,例如:D:\Java\m2\repository: 在windows的环境变量中增加了新的用户变量M2_REPO,其对应的值为D:\Java\m2\rep ...

  4. 如何在fluid中添加自定义控件

    fluid中已经有它自己自带的控件,那如何让我们自定义的控件放到fluid中呢,这里有两种方法,一种是修改fluid代码,一种是以另外的控件来代替自定义的控件,只是在代替控件属性的class选项下填写 ...

  5. UA MATH567 高维统计专题1 稀疏信号及其恢复6 随机设计矩阵下LASSO的估计误差

    UA MATH567 高维统计专题1 稀疏信号及其恢复6 随机设计矩阵下LASSO的估计误差 上一讲我们推导了noisy setting下LASSO估计误差的阶O(slog⁡d/n)O(\sqrt{s ...

  6. 自定义控件只允许输入Decimal和int类型字符串

    为什么80%的码农都做不了架构师?>>>    自定义控件中只放了一个TextBox控件,并在TextBox下利用自定义控件的Paint画了一条线,然后给TextBox做了3个自定义 ...

  7. WinCE下直接启动自己应用程序的方法

    WinCE下直接启动自己应用程序的方法 WinCE下直接启动自己应用程序的方法 其实让一个程序在wince里启动和windows里差不多,直接设置其为启动项,这个有几个方法.一个就是制作一个快捷方式, ...

  8. openwrt源码分析_Luci流程分析(openwrt下)

    1.页面请求: 1.1.代码结构 在openwrt文件系统中,lua语言的代码不要编译,类似一种脚本语言被执行,还有一些uhttpd服务器的主目录,它们是: /www/index.html cgi-b ...

  9. 一种崭新的长尾分布下分类问题的通用算法|NeurIPS 2020

    ↑ 点击蓝字 关注视学算法 作者丨汤凯华@知乎 来源丨https://zhuanlan.zhihu.com/p/259569655 编辑丨极市平台 本文主要介绍我们组今年被NeurIPS 2020接收 ...

最新文章

  1. VRRP在企业网中的应用(H3C设备)
  2. ssh mysql环境搭建 myeclipse_MyEclipse整合ssh三大框架环境搭载用户注册源码下载
  3. 基于loudmouth的XMPP客户端DEMO
  4. Python+selenium 自动化-mac下安装配置chrome驱动方法
  5. Python数据结构与算法(第一天)
  6. [Asp.net]站点地图SiteMap
  7. 继续Bargaining
  8. 清明出游,在高速上堵了16个小时。
  9. [转载] 使用selenium_一日一技:使用Selenium的浏览器自动化
  10. Mysql缺少可执行的命令
  11. linux下目录的基本命令
  12. 我应该通过软件或硬件调整音量以获得最佳声音吗?
  13. Interior-point methods(内点法)学习笔记
  14. 专访邱锡鹏:人工智能开源社区的「先行者」
  15. Java对pdf文件进行压缩打包并执行下载
  16. 京东云安装docker
  17. 反算坐标方位角小程序(c#)
  18. Excel信息批量替换Word模板生成新文件
  19. 植物识别扫一扫的软件有哪些?植物识别软件推荐。
  20. ubuntu删除旧的linux内核

热门文章

  1. Burp Post、Get数据包转为上传multipart/form-data格式数据包
  2. [SDOI2013]直径
  3. ormlite更改数据库默认位置
  4. bash的快捷键、特殊参数、历史命令、相关文件
  5. 云服务被归类为IDC业务 提供云服务必须持证上岗
  6. 让世界没有陌生的角落共享单车时代的快与慢
  7. varnish与squid的比较
  8. Beetl 性能揭秘 1 :如何输出一个整型变量
  9. Druid 不仅仅是一个数据库连接池
  10. ELKElasticSearch5.1基础概念及配置文件详解【转】