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

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

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

那么老规矩,上效果图:

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

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

  1. public WaveView(Context context) {
  2. this(context, null);
  3. }
  4.  
  5. public WaveView(Context context, AttributeSet attrs) {
  6. this(context, attrs, 0);
  7. }
  8.  
  9. public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
  10. super(context, attrs, defStyleAttr);
  11. mContext = context;
  12. TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.WaveView,defStyleAttr,0);
  13. mWaveCount = a.getInt(R.styleable.WaveView_waveCount,10);
  14. mWaveWidth = a.getInt(R.styleable.WaveView_waveWidth,20);
  15. mMode = a.getInteger(R.styleable.WaveView_mode,-2);
  16. mColor = a.getColor(R.styleable.WaveView_android_color,Color.parseColor("#2C97DE"));
  17.  
  18. }

自定义属性如下 attr.xml:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <declare-styleable name="WaveView">
  4. <attr name="waveCount" format="integer"/>
  5. <attr name="waveWidth" format="integer"/>
  6. <attr name="android:color"/>
  7. <attr name="mode" >
  8. <enum name = "circle" value="-1"/>
  9. <enum name = "triangle" value = "-2"/>
  10. </attr>
  11. </declare-styleable>
  12. </resources>

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

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

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  4. int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  5. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  6. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  7. //矩形宽度为view的80%
  8. if (widthMode == MeasureSpec.EXACTLY) {
  9. mWidth = widthSize;
  10.  
  11. mRectWidth = (float) (mWidth * 0.8);
  12.  
  13. //如果是wrap_content 直接给一个定值
  14. }else if(widthMode == MeasureSpec.AT_MOST){
  15. mWidth = PxUtils.dpToPx(300,mContext);
  16.  
  17. mRectWidth = (float) (mWidth * 0.8);
  18.  
  19. }
  20.  
  21. //矩形高度为view的80%
  22. if (heightMode == MeasureSpec.EXACTLY) {
  23. mHeight = heightSize;
  24. mRectHeight = (float) (mHeight * 0.8);
  25. //如果是wrap_content 直接给一个定值
  26. }else if(heightMode == MeasureSpec.AT_MOST){
  27.  
  28. mHeight = PxUtils.dpToPx(200,mContext);
  29.  
  30. mRectHeight = (float) (mHeight * 0.8);
  31. }
  32.  
  33. setMeasuredDimension(mWidth, mHeight);
  34. }

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

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

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

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

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

  1. protected void onDraw(Canvas canvas) {
  2. Paint p = new Paint();
  3. p.setColor(mColor);
  4.  
  5. //计算每个三角形的高
  6. mWaveHeight = mRectHeight / mWaveCount;
  7.  
  8. //绘制矩形
  9.  
  10. //计算padding
  11. float padding = ((mWidth - mRectWidth) / 2);
  12. canvas.drawRect(padding, padding, mRectWidth + padding, mRectHeight + padding, p);

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

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

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

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

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

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

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

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

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

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

新手自定义view练习实例之(二) 波浪view的更多相关文章

  1. Android View框架总结(二)View焦点

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52263256 前言:View框架写到第六篇,发现前面第二篇竟然没有, ...

  2. 【朝花夕拾】Android自定义View篇之(一)View绘制流程

    前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...

  3. Autodesk View and Data API二次开发学习指南

    什么是View and Data API? 使用View and Data API,你可以轻松的在网页上显示大型三维模型或者二维图纸而不需要安装任何插件.通过View and Data API,你可以 ...

  4. python学习_数据处理编程实例(二)

    在上一节python学习_数据处理编程实例(二)的基础上数据发生了变化,文件中除了学生的成绩外,新增了学生姓名和出生年月的信息,因此将要成变成:分别根据姓名输出每个学生的无重复的前三个最好成绩和出生年 ...

  5. C语言库函数大全及应用实例十二

    原文:C语言库函数大全及应用实例十二                                          [编程资料]C语言库函数大全及应用实例十二 函数名: setrgbpalette ...

  6. java学习--自定义类的实例的大小比较和排序

    我们知道Object类有一个equals方法,用于比较两个对象是否相等 我们只要在自定义类中重写了equals方法(若不重写就是比较两个实例的地址,相当于==)就可以用来比较该类的两个实例是否相等 问 ...

  7. 【微信小程序】自定义模态框实例

    原文链接:https://mp.weixin.qq.com/s/23wPVFUGY-lsTiQBtUdhXA 1 概述 由于官方API提供的显示模态弹窗,只能简单地显示文字内容,不能对对话框内容进行自 ...

  8. Qt5MV自定义模型与实例浅析

    1. Model/View结构 这种结构,其实就是将界面组件与所编辑的数据分离开来,又通过数据源的方式连接起来,相当于解耦,视图层只关心显示和与用户交互,而数据层负责与实际的数据进行通信,并为视图组件 ...

  9. SQL Server 2008 数据库镜像部署实例之二 配置镜像,实施手动故障转移

    SQL Server 2008 数据库镜像部署实例之二 配置镜像,实施手动故障转移 上一篇文章已经为配置镜像数据库做好了准备,接下来就要进入真正的配置阶段 一.在镜像数据库服务器上设置安全性并启动数据 ...

随机推荐

  1. Jmeter(二)_基础元件

    测试计划(Test Plan) 它用来描述一个测试方案,包含与本次性能测试所有相关的功能.也就说本次测试的所有内容是于基于一个计划的. "函数测试模式"复选框,如果被选择,它会使J ...

  2. Bootstrap3 表格-状态类

    通过这些状态类可以为行或单元格设置颜色. .active---鼠标悬停在行或单元格上时所设置的颜色 .success--–标识成功或积极的动作 .info----标识普通的提示信息或动作 .warni ...

  3. O(1)空间内实现矩阵转置

    思路:  * 每个元素转置前后会形成一个环(一个数字有多个环)  * 利用环来移动元素达到转置  * 关键:  * 1.得到元素下标的前驱后继,  * 2.判断环是否已走过(意味属于一个环的元素一次转 ...

  4. Dynamics CRM build numbers

    Dynamics CRM build numbers CRM各大版本及补丁列表,整理的很全

  5. Docker简介/安装/使用

    什么是Docker?docker是一个开源的应用容器引擎,系统级的轻量虚拟化技术.应用程序的自动化部署解决方案,能够迅速创建一个容器,并在容器上部署和运行应用程序,并通过配置文件可以轻松实现应用程序的 ...

  6. static 变量(静态变量)

    在C++的面向对象编程中,static还可以加在类的数据成员或成员函数之前.这样定义的数据成员或成员函数就被类所拥有,而不再属于类的对象. #include <iostream> usin ...

  7. Swift如何取得View所属的ViewController

    从VC取得View很容易,但有些情况下我们需要从View反向获取VC. 不过在一些特殊的场合,Cocoa库帮我们想的很周到,比如在自定义View过渡动画的时候: func animateTransit ...

  8. 关于React Native项目在android上UI性能调试实践

    我们尽最大的努力来争取使UI组件的性能如丝般顺滑,但有的时候这根本不可能做到.要知道,Android有超过一万种不同型号的手机,而在框架底层进行软件渲染的时候是统一处理的,这意味着你没办法像iOS那样 ...

  9. Android文本框-android学习之旅(十七 )

    文本框简介 文本框属于基本的andoid控件,TextView继承了View是最基本的文本框,它的子类包括EditView和Button等,TextView的大部分方法,它的子类也可以使用. Text ...

  10. parcel和parcelable

    Parcel 在英文中有两个意思,其一是名词,为包裹,小包的意思: 其二为动词,意为打包,扎包.邮寄快递中的包裹也用的是这个词.Android采用这个词来表示封装消息数据.这个是通过IBinder通信 ...