本篇文章讲的是自定义View之边缘凹凸的优惠券效果,之前有见过很多优惠券的效果都是使用了边缘凹凸的样式。和往常一样,主要总结一下在自定义View的开发过程中需要注意的一些地方。

按照惯例,我们先来看看效果图

一、写代码之前,我们先弄清楚view的启动过程:
之所以想要弄清楚这个问题是因为代码里面用到了onSizeChanged()方法,一开始我有点犹豫onSizeChanged是在什么时候启动的呢,所以看看View的启动流程吧

package per.lijuan.coupondisplayviewdome;import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;/*** 自定义边缘凹凸的优惠券效果view* Created by lijuan on 2016/9/26.*/
public class CouponDisplayView extends LinearLayout {public CouponDisplayView(Context context) {this(context, null);Log.d("mDebug", "CouponDisplayView:context");}public CouponDisplayView(Context context, AttributeSet attrs) {this(context, attrs, 0);Log.d("mDebug", "CouponDisplayView:context,attrs");}public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);Log.d("mDebug", "CouponDisplayView:context,attrs,defStyleAttr");}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);Log.d("mDebug", "onSizeChanged:w=" + w + ",h=" + h + ",oldw=" + oldw + ",oldh=" + oldh);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Log.d("mDebug", "onDraw");}}

输出如下:

09-27 15:29:31.957 8210-8210/per.lijuan.coupondisplayviewdome D/mDebug: CouponDisplayView:context,attrs,defStyleAttr
09-27 15:29:31.957 8210-8210/per.lijuan.coupondisplayviewdome D/mDebug: CouponDisplayView:context,attrs
09-27 15:29:32.050 8210-8210/per.lijuan.coupondisplayviewdome D/mDebug: onSizeChanged:w=984,h=361,oldw=0,oldh=0
09-27 15:29:32.083 8210-8210/per.lijuan.coupondisplayviewdome D/mDebug: onDraw

在这里可以看到,onSizeChanged()方法的启动是在onDraw之前

二、view的几个常用触发方法
1. onFinishInflate():当View中所有的子控件均被映射成xml后触发
2. onMeasure(int widthMeasureSpec, int heightMeasureSpec):确定所有子元素的大小
3. onLayout(boolean changed, int l, int t, int r, int b):当View分配所有的子元素的大小和位置时触发
4. onSizeChanged(int w, int h, int oldw, int oldh):当view的大小发生变化时触发
5. onDraw(Canvas canvas):负责将View绘制在屏幕上

三、View 的几个构造函数
1、public CouponDisplayView(Context context)
—>Java代码直接new一个CouponDisplayView实例的时候,会调用这个只有一个参数的构造函数;

2、public CouponDisplayView(Context context, AttributeSet attrs)
—>在默认的XML布局文件中创建的时候调用这个有两个参数的构造函数。AttributeSet类型的参数负责把XML布局文件中所自定义的属性通过AttributeSet带入到View内;

3、public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr)
—>构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或者Activity所用的Theme中的默认Style,且只有在明确调用的时候才会调用

4、public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
—>该构造函数是在API21的时候才添加上的

自定义View中,我们需要重写了3个构造方法,在上面的构造方法中说过默认的布局文件调用的是两个参数的构造方法,所以记得让所有的构造方法调用三个参数的构造方法,然后在三个参数的构造方法中获得自定义属性。
一开始一个参数的构造方法和两个参数的构造方法是这样的:

    public CouponDisplayView(Context context) {super(context);}public CouponDisplayView(Context context, AttributeSet attrs) {super(context, attrs);}

我们需要注意的是super应该改成this,然后让一个参数的构造方法引用两个参数的构造方法,两个参数的构造方法引用三个参数的构造方法,代码如下:

public CouponDisplayView(Context context) {this(context, null);}public CouponDisplayView(Context context, AttributeSet attrs) {this(context, attrs, 0);}

四、分析具体的实现思路:
从上面的效果图来看,这个自定义View和普通的Linearlayout,RelativeLayout一样,只是上下两边多了类似于半圆锯齿的形状,我们需要在上下两条线上画一个个白色的小圆来实现这种效果。

假如我们上下线的半圆以及半圆与半圆之间的间距是固定的,那么不同尺寸的屏幕肯定会画出不同数量的半圆,那么我们只需要根据控件的宽度来获取能画的半圆数。

我们观察效果图会发现,圆的数量总是圆间距数量-1,也就是说,假设圆的数量是circleNum,那么圆间距就是circleNum+1,所以我们可以根据这个计算出circleNum:

circleNum = (int) ((w-gap)/(2*radius+gap)); 

这里gap就是圆间距,radius是圆半径,w是view的宽。

五、下面我们就开始来看看代码啦
1、自定义View的属性,首先在res/values/ 下建立一个attr.xml , 在里面定义我们的需要用到的属性以及声明相对应属性的取值类型

<?xml version="1.0" encoding="utf-8"?>
<resources><!--圆间距--><attr name="radius" format="dimension" /><!--半径--><attr name="gap" format="dimension" /><declare-styleable name="CouponDisplayView"><attr name="radius" /><attr name="gap" /></declare-styleable></resources>

我们定义了圆间距和半径2个属性,format是值该属性的取值类型,format取值类型总共有10种,包括:string,color,demension,integer,enum,reference,float,boolean,fraction和flag。

2、然后在XML布局中声明我们的自定义View

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:custom="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="16dp"><per.lijuan.coupondisplayviewdome.CouponDisplayView
        android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#FBB039"android:orientation="horizontal"android:padding="16dp"custom:gap="8dp"custom:radius="5dp"><ImageView
            android:layout_width="90dp"android:layout_height="match_parent"android:scaleType="centerCrop"android:src="@mipmap/ic_launcher" /><LinearLayout
            android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:orientation="vertical"><TextView
                android:id="@+id/name"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="电影新客代金劵"android:textSize="18dp" /><TextView
                android:layout_width="match_parent"android:layout_height="wrap_content"android:paddingTop="5dp"android:text="编号:525451122312431"android:textSize="12dp" /><TextView
                android:layout_width="match_parent"android:layout_height="wrap_content"android:paddingTop="5dp"android:text="满200元可用、限最新版本客户端使用"android:textSize="12dp" /><TextView
                android:layout_width="match_parent"android:layout_height="wrap_content"android:paddingTop="5dp"android:text="截止日期:2016-11-07"android:textSize="12dp" /></LinearLayout></per.lijuan.coupondisplayviewdome.CouponDisplayView>
</LinearLayout>

一定要引入xmlns:custom=”http://schemas.android.com/apk/res-auto”,Android Studio中我们可以使用res-atuo命名空间,就不用添加自定义View全类名。

3、在View的构造方法中,获得我们的xml布局文件中定义的圆的半径和圆间距

private Paint mPaint;/*** 半径*/private float radius=10;/*** 圆间距*/private float gap=8;/*** 圆数量*/private int circleNum;private float remain;public CouponDisplayView(Context context) {this(context, null);Log.d("mDebug", "CouponDisplayView context");}public CouponDisplayView(Context context, AttributeSet attrs) {this(context, attrs, 0);Log.d("mDebug", "CouponDisplayView context, attrs");}public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);Log.d("mDebug", "CouponDisplayView context,attrs,defStyleAttr");/*** 获得我们所定义的自定义样式属性*/TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CouponDisplayView, defStyleAttr, 0);for (int i = 0; i < a.getIndexCount(); i++) {int attr = a.getIndex(i);switch (attr) {case R.styleable.CouponDisplayView_radius:radius = a.getDimensionPixelSize(R.styleable.CouponDisplayView_radius, 10);break;case R.styleable.CouponDisplayView_gap:gap = a.getDimensionPixelSize(R.styleable.CouponDisplayView_radius, 8);break;}}a.recycle();mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setDither(true);mPaint.setColor(Color.WHITE);mPaint.setStyle(Paint.Style.FILL);}

4、重写onSizeChanged()方法,根据上面的圆的半径和圆间距来计算需要画的圆数量circleNum

@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);Log.d("mDebug", "onSizeChanged,w=" + w + ",h=" + h + ",oldw=" + oldw + ",oldh=" + oldh);if (remain == 0) {//计算不整除的剩余部分remain = (int) (w - gap) % (2 * radius + gap);}circleNum = (int) ((w - gap) / (2 * radius + gap));}

5、接下来只需要重写onDraw()方法,简单的根据circleNum的数量将一个一个的圆绘制在屏幕上就可以了

 @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Log.d("mDebug", "onDraw");for (int i = 0; i < circleNum; i++) {float x = gap + radius + remain / 2 + ((gap + radius * 2) * i);canvas.drawCircle(x, 0, radius, mPaint);canvas.drawCircle(x, getHeight(), radius, mPaint);}}

这里remain/2是因为避免有一些情况:当计算出来的圆的数量不是整除时,这样就会出现右边最后一个间距会比其它的间距都要宽,所以我们在绘制第一个的时候加上了余下的间距的一半,即使是不整除的情况,至少也能保证第一个和最后一个间距宽度一致。

好了,本篇文章已经全部写完了,存在总结不到位的地方还望指导,感谢^_^

源码下载

参考资料:
http://blog.csdn.net/yissan/article/details/51429281

Android 自定义View之边缘凹凸的优惠券效果相关推荐

  1. android代码实现手机加速功能,Android自定义View实现内存清理加速球效果

    Android自定义View实现内存清理加速球效果 发布时间:2020-09-21 22:21:57 来源:脚本之家 阅读:105 作者:程序员的自我反思 前言 用过猎豹清理大师或者相类似的安全软件, ...

  2. Android 抖音爱心动画,Android自定义View实现抖音飘动红心效果

    本文实例为大家分享了Android自定义View实现抖音飘动红心效果的具体代码,供大家参考,具体内容如下 自定义View--抖音飘动红心 效果展示 动画效果 使用自定义view完成红心飘动效果 Vie ...

  3. android自定义radiogroup,Android 自定义View实现任意布局的RadioGroup效果

    前言 RadioGroup是继承LinearLayout,只支持横向或者竖向两种布局.所以在某些情况,比如多行多列布局,RadioGroup就并不适用 . 本篇文章通过继承RelativeLayout ...

  4. android 自定义红心,Android自定义View实现抖音飘动红心效果

    本文实例为大家分享了Android自定义View实现抖音飘动红心效果的具体代码,供大家参考,具体内容如下 自定义View--抖音飘动红心 效果展示 动画效果 使用自定义view完成红心飘动效果 Vie ...

  5. android 自定义加载动画效果,Android自定义View实现loading动画加载效果

    项目开发中对Loading的处理是比较常见的,安卓系统提供的不太美观,引入第三发又太麻烦,这时候自己定义View来实现这个效果,并且进行封装抽取给项目提供统一的loading样式是最好的解决方式了. ...

  6. android 高仿 探探卡片滑动,Android自定义View仿探探卡片滑动效果

    Android自定义View仿探探卡片滑动这种效果网上有很多人已经讲解了实现思路,大多都用的是RecyclerView来实现的,但是我们今天来换一种实现思路,只用一个自定义的ViewGroup来搞定这 ...

  7. Android自定义View(四)——仿Android5.0波纹效果

    项目源码比较简单,直接看帖的代码就可以了. 说实话,我是真没有去看RippleView的源码,只是从表面看到它的效果,所以产生了一点思路,所以功能很有局限性,而且用起来也比较复杂,大家且看且喷就好^_ ...

  8. Android自定义View——仿网易云音乐留声机效果

    //自定义类 public class GramophoneView extends View {/*** 尺寸计算设计说明:* 1.唱片有两个主要尺寸:中间图片的半径.黑色圆环的宽度.* 黑色圆环的 ...

  9. Android自定义View之ListView实现时间轴效果:我只是个送快递的。

    先上效果图: 实现时间轴的原理 listview的基本使用,相信大家都很熟悉.先在layout下新建一个xml布局文件,对应一个子项的listView的显示内容.在上面的图我们可以看到,每一项都是 有 ...

最新文章

  1. ecshop目录结构
  2. 【计算机网络】深入浅出网络层(看不懂你来打我.上)
  3. ubuntu部署eclipse兼容性问题
  4. STM32下SysTick的一个容易发生的错误,时钟频率设置
  5. BigDecimal类基础
  6. xrkmonitor监控mysql_xrkmonitor字符云监控系统
  7. 格式化显示(日期\货币)
  8. dev代码拷贝中文乱码的解决方案
  9. size()计算jquery对象中元素的个数
  10. 建立完善的员工晋升机制_员工晋升机制(完)
  11. antd + react model自定义footer_阿里开源可插拔的企业级React应用框架——UmiJS
  12. Tomcat8安装及配置步骤
  13. win10 android模拟器 菜单,Win10 Android模拟器教程
  14. push declined due to email privacy restrictions (GH007 error code) 解决方法
  15. 用计算机算锐角三角比,锐角三角比中计算器使用方法ppt
  16. AndroidQ文件存储适配
  17. 九九乘法表居中c语言,JavaScript实现九九乘法表的简单实例
  18. 一个游戏开发者,向苹果宣战!
  19. vivo X90和iPhone 14哪个好 vivo X90 和苹果14 区别对比评测
  20. 一个虎扑社区数据分析实战

热门文章

  1. t3提示本地系统高于服务器,登录T3软件时,提示本地版本高于服务器已升级版本...
  2. CentOS Stream才是未来
  3. [LeetCode/Scala] 第188场周赛
  4. 关于网狐棋牌的数据库
  5. oracle EM的安装配置
  6. 异常行为检测算法_检测异常行为的异常或异常类型算法
  7. 安卓屏幕适配——pt适配,将pt作为宽度百分比单位
  8. Python基础教程—私有化
  9. linux三国杀,三国杀!Linux、openSUSE和Ubuntu对比
  10. 审稿周期较快的SCI期刊总结:人工智能,神经网络,CV