本系列是为新手准备的自定义view练习项目(大牛请无视),相信在学习过程中,想学自定义view又无从下手,不知道做什么。本系列为新手提供了一系列自定义view的简单实例。看过理解之后,自己实现,相信会有很大提高。

转载请注明本篇出处:http://blog.csdn.net/wingichoy/article/details/50460213

继续来本系列的第二篇,启发是吃口香糖看到了包装纸,觉得挺好看,就想画一个出来#职业病#,本次的目标是做一个波浪形状的view,可以是尖角,也可以是圆角。

那么老规矩,上效果图:

聪明的你一眼就看出来了,不就是个矩形加好多三角嘛。答对了,就是这么简单,事不宜迟,快拿起武器动手练一练。毕竟程序员的秘诀就是“无他,唯手熟尔”。

首先,新建一个类 起名为WaveView 继承自View,重写他的构造方法,在第三个构造方法里获取自定义属性。

 public WaveView(Context context) {
this(context, null);
} public WaveView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.WaveView,defStyleAttr,0);
mWaveCount = a.getInt(R.styleable.WaveView_waveCount,10);
mWaveWidth = a.getInt(R.styleable.WaveView_waveWidth,20);
mMode = a.getInteger(R.styleable.WaveView_mode,-2);
mColor = a.getColor(R.styleable.WaveView_android_color,Color.parseColor("#2C97DE")); }

自定义属性如下 attr.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="WaveView">
<attr name="waveCount" format="integer"/>
<attr name="waveWidth" format="integer"/>
<attr name="android:color"/>
<attr name="mode" >
<enum name = "circle" value="-1"/>
<enum name = "triangle" value = "-2"/>
</attr>
</declare-styleable>
</resources>

这些都没有什么好说的,你一定已经轻车熟路。

然后重写他的onMeasure()  来告诉系统这个view有多大。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//矩形宽度为view的80%
if (widthMode == MeasureSpec.EXACTLY) {
mWidth = widthSize; mRectWidth = (float) (mWidth * 0.8); //如果是wrap_content 直接给一个定值
}else if(widthMode == MeasureSpec.AT_MOST){
mWidth = PxUtils.dpToPx(300,mContext); mRectWidth = (float) (mWidth * 0.8); } //矩形高度为view的80%
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = heightSize;
mRectHeight = (float) (mHeight * 0.8);
//如果是wrap_content 直接给一个定值
}else if(heightMode == MeasureSpec.AT_MOST){ mHeight = PxUtils.dpToPx(200,mContext); mRectHeight = (float) (mHeight * 0.8);
} setMeasuredDimension(mWidth, mHeight);
}

准备工作大致已经完成,接下来开始绘图。首先 画一个矩形。

这个矩形让他处于view的中间,看图:

由图可知, 矩形的左上坐标为 padding ,padding 矩形的右下坐标为padding +mRectWidth, padding + mRectHeight

其中padding 为 (mWidth - mRectWidth)/2   注意这里只是左右padding 为了简易 就不计算上下padding了。

所以我们先将矩形绘制出来,如下图:   可以看到左右padding是相等的,上下不等,这是因为上面只计算了左右padding

 protected void onDraw(Canvas canvas) {
Paint p = new Paint();
p.setColor(mColor); //计算每个三角形的高
mWaveHeight = mRectHeight / mWaveCount; //绘制矩形 //计算padding
float padding = ((mWidth - mRectWidth) / 2);
canvas.drawRect(padding, padding, mRectWidth + padding, mRectHeight + padding, p);

绘制矩形完毕,需要来一个判断,判断当前模式是圆角还是尖角

 if(mMode == MODE_TRIANGLE) {}else{}

我们首先来绘制尖角,还记得上一篇泡泡窗的那个三角吗,我们只要画多次不就形成波浪了吗,所以用循环就可以搞定。坐标计算如下:

矩形的右上角暂定为 StartX,StartY    三角形的宽度为 mWaveWidth  高度为 mWaveHeight  那么还是用path来画,首先将path MoveTo startX,startY 然后计算得出各个坐标,在用一个i来代表第几个三角形来做循环,代码如下:

if(mMode == MODE_TRIANGLE) {
//绘制右边的波浪
float startX = padding + mRectWidth;
float startY = padding;
Path path = new Path();
path.moveTo(startX, startY);
for (int i = 0; i < mWaveCount; i++) {
path.lineTo(startX + mWaveWidth, startY + i * mWaveHeight + (mWaveHeight / 2));
path.lineTo(startX, startY + mWaveHeight * (i + 1)); }
path.close();
canvas.drawPath(path, p);

只要把上面的坐标带入进去即可,那么左边的波浪只是改变了一个x坐标的加减值,也很简单。

  //绘制左边的波浪
startX = padding;
startY = padding;
path.moveTo(startX, startY);
for (int i = 0; i < mWaveCount; i++) {
path.lineTo(startX - mWaveWidth, startY + i * mWaveHeight + (mWaveHeight / 2));
path.lineTo(startX, startY + mWaveHeight * (i + 1));
} path.close();
canvas.drawPath(path, p);

这样便完成了整个波浪view的绘制。本篇就到此结束了。

别急,我没忘圆形模式,这里给大家留个家庭作业,大家下去根据这个思路自己把圆形波浪画出来吧~ 毕竟只有多练,才能提高

本项目github地址:点击打开链接 ,求关注,求评论,求star

最新文章

  1. 把office文档转换为html过程中的一些坑
  2. python进阶笔记 thread 和 threading模块学习
  3. &lt;随便写写&gt;
  4. AndroidManifest.xml的android:name是否带.的区别
  5. package
  6. UIStepper swift
  7. CSS基础(03)
  8. 【转】Ubuntu 修改hosts
  9. 多个Activity之间的切换与数据交互
  10. Android开发之使用Handler封装下载图片工具类(源码分享)
  11. PHP学习笔记-4(时间戳)
  12. 201521123039 《java程序设计》第十二周学习总结
  13. SpringBoot多数据源配置
  14. 一起talk C栗子吧(第一百二十六回:C语言实例--statickeyword)
  15. luogu【P1144】最短路计数
  16. 机器学习技法:08 Adaptive Boosting
  17. 工控随笔_16_西门子_S7-200.Smart软件安装兼容性说明和错误代码:error code hr=0x80070430
  18. python之常用模块(续)
  19. Shell基础知识(六)
  20. 仿QQ聊天图文混排流程图【适用于XMPP】

热门文章

  1. sublimetext 自定义build
  2. Python强大的可变参数传递机制
  3. Bootstrap3 排版-内联文本元素
  4. Bootstrap3 栅格系统-嵌套列
  5. Scikit-learn:分类classification
  6. Ubuntu下装QQ2014(http://my.oschina.net/oscfox/blog/315951)
  7. 有N个数,组成的字符串,如012345,求出字串和取MOD3==0的子串,如012 12 123 45。
  8. Nginx的负载均衡 - 保持会话 (ip_hash)
  9. linux的 压缩与解压 命令集
  10. 关于React Native 安卓首屏白屏优化