最近需要实现一个凹凸效果的拟物化优惠券效果,我一看,本来想用.9图片做背景实现的,虽说图片做背景实现省事儿方便,但是能用代码实现最好不过了,最终我还是选择了用代码来实现,于是有了下文。

最终效果图

demo下载地址

###1.完整代码 先看完整的代码,后面我们再对代码逐一的解释

public class CouponDisplayView extends RelativeLayout {private Paint mPaint;private Paint mPaint2;
// 圆间距private float gap = 0;
// 半径private float radius = 20;
// 圆数量private int circleNum;private float remain;private int color;public CouponDisplayView(Context context) {super(context);}public CouponDisplayView(Context context, AttributeSet attrs) {super(context, attrs);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setDither(true);mPaint.setColor(color);mPaint.setStyle(Paint.Style.FILL);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (remain == 0) {remain = (int) (w - gap) % (2 * radius + gap);}circleNum = (int) ((w - gap) / (2 * radius + gap));}public CouponDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int i = 0; i < circleNum; i++) {float x = gap + radius + remain / 2 + ((gap + radius * 2) * i);canvas.drawCircle(x, 0, radius, mPaint);}mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint2.setDither(true);mPaint2.setColor(getResources().getColor(R.color.divider_color_car));mPaint2.setStyle(Paint.Style.FILL);Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.DKGRAY);Path path = new Path();path.moveTo(0, getHeight() / 2 + 60);path.lineTo(getWidth(), getHeight() / 2 + 60);PathEffect effects = new DashPathEffect(new float[]{15, 15, 15, 15}, 2);paint.setPathEffect(effects);canvas.drawPath(path, paint);canvas.drawCircle(0, getHeight() / 2 + 60, radius, mPaint2);canvas.drawCircle(getWidth(), getHeight() / 2 + 60, radius, mPaint2);}public void setColor(int color) {this.color = color;}
}
复制代码

###2.方法解释 1、CouponDisplayView继承自RelativeLayout,通过打印日志测试已知View的执行顺序如下:

CouponDisplayView(context,attrs,defStyleAttr)
CouponDisplayView(context,attrs)
onSizeChanged()
onDraw()
复制代码

onSizeChanged(int w, int h, int oldw, int oldh) 当view的大小发生变化时触发 onDraw(Canvas canvas) 负责将View绘制在屏幕上 public CouponDisplayView(Context context) Java代码直接new一个CouponDisplayView实例的时候,会调用这个只有一个参数的构造函数 public CouponDisplayView(Context context, AttributeSet attrs) 在默认的XML布局文件中创建的时候调用这个有两个参数的构造函数。AttributeSet类型的参数负责把XML布局文件中所自定义的属性通过AttributeSet带入到View内; public CouponDisplayView(Context context,AttributeSet attrs, int defStyleAttr) 构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或者Activity所用的Theme中的默认Style,且只有在明确调用的时候才会调用

###3.代码实现思路 从上面的效果图来看,这个自定义View和普通的Linearlayout,RelativeLayout一样,只是上下两边多了类似于半圆锯齿的形状,我们需要在上下两条线上画一个个白色的小圆来实现这种效果。 假如我们上下线的半圆以及半圆与半圆之间的间距是固定的,那么不同尺寸的屏幕肯定会画出不同数量的半圆,那么我们只需要根据控件的宽度来获取能画的半圆数。 我们观察效果图会发现,圆的数量总是圆间距数量-1,

也就是说,假设圆的数量是circleNum,那么圆间距就是circleNum+1,所以我们可以根据这个计算出circleNum: 这里gap就是圆间距,radius是圆半径,w是view的宽

circleNum = (int) ((w-gap)/(2*radius+gap));
复制代码

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

    @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (remain == 0) {remain = (int) (w - gap) % (2 * radius + gap);}circleNum = (int) ((w - gap) / (2 * radius + gap));}
复制代码

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

    @Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int i = 0; i < circleNum; i++) {float x = gap + radius + remain / 2 + ((gap + radius * 2) * i);canvas.drawCircle(x, 0, radius, mPaint);}
}
复制代码

3.画中间的黑色虚线

  Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.DKGRAY);Path path = new Path();path.moveTo(0, getHeight() / 2 + 60);path.lineTo(getWidth(), getHeight() / 2 + 60);PathEffect effects = new DashPathEffect(new float[]{15, 15, 15, 15}, 2);paint.setPathEffect(effects);canvas.drawPath(path, paint);
复制代码

4.画两边居中的半圆

    mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint2.setDither(true);mPaint2.setColor(getResources().getColor(R.color.divider_color_car));mPaint2.setStyle(Paint.Style.FILL);canvas.drawCircle(0, getHeight() / 2 + 60, radius, mPaint2);canvas.drawCircle(getWidth(), getHeight() / 2 + 60, radius, mPaint2);
复制代码

代码分析完毕

###3.设置自定义样式属性

考虑到复用地方不是很多,所以上面的代码没有写自定义样式属性,而是用了public void setColor(int color) {this.color = color;}有需要设置自定义属性的我在这里写一下哈,嘻嘻

1、在res/values/ 下建立一个attr.xml , 在里面定义我们的需要用到的属性以及声明相对应属性的取值类型

<?xml version="1.0" encoding="utf-8"?>
<resources>//半圆颜色<attr name="radiusColor" format="color" /><declare-styleable name="CouponDisplayView"><attr name="radiusColor" /></declare-styleable></resources>
复制代码

上面定义的半圆颜色的属性,format属性的取值类型总共有10种,包括:stringcolordemensionintegerenumreferencefloatbooleanfractionflag

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">
<--注意:一定要引入xmlns:custom="http://schemas.android.com/apk/res-auto"
custom名字可以自定义--><com.xxx.xxx.CouponDisplayViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="#FBB039"android:orientation="horizontal"android:padding="16dp"custom:radiusColor="@Color/red">
............</com.xxx.xxx.CouponDisplayView>
</LinearLayout>
复制代码

3、在View的构造方法中,获得我们的xml布局文件中定义的颜色

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_radiusColor:radius = a.getDimensionPixelSize(R.styleable.CouponDisplayView_radiusColor, 10);break;}}a.recycle();
}
复制代码

OK,设置自定义样式属性到此就写完了。

转载于:https://juejin.im/post/5bdda7e451882516bb02e11b

android自定义布局实现优惠券效果相关推荐

  1. Android 自定义 圆环,Android自定义view实现圆环效果实例代码

    先上效果图,如果大家感觉不错,请参考实现代码. 重要的是如何实现自定义的view效果 (1)创建类,继承view,重写onDraw和onMesure方法 public class CirclePerc ...

  2. android中仿qq最新版抽屉,Android 自定义View实现抽屉效果

    Android 自定义View实现抽屉效果 说明 这个自定义View,没有处理好多点触摸问题 View跟着手指移动,没有采用传统的scrollBy方法,而是通过不停地重新布局子View的方式,来使得子 ...

  3. android波纹效果弹窗,Android自定义View实现波纹效果

    Android自定义View实现波纹效果 时间:2017-05-27     来源:移动互联网学院 1.引言:随着Android智能手机的普及,Android应用得到了大力支持,而Android应用的 ...

  4. android 循环弹幕,Android自定义View实现弹幕效果

    原标题:Android自定义View实现弹幕效果 在很多视频直播中都有弹幕功能,而安卓上没有简单好用的弹幕控件,本文介绍一个自定义弹幕view的demo. 效果图: 思路: 自定义Textitem类表 ...

  5. android下雨动画效果,Android 自定义View(二) 下雨效果

    Rain.gif Android 自定义View(二) 下雨效果 一 实现思路, 雨点用线段表示,通过控制线段的大小和宽度来表示不同的线段. 一个雨点下雨的过程可以表示为一条直线,一次雨点在下雨的过程 ...

  6. android功能相同的view,Android自定义View实现扫描效果

    本文实例为大家分享了Android自定义View实现扫描效果的具体代码,供大家参考,具体内容如下 演示效果如下: 实现内容: 1.控制动画是竖向或者横向 2.控制动画初始是从底部/左边开始,或者从上边 ...

  7. android 自定义布局 根据布局获取类,android自定义布局中的平滑移动之ViewGroup实现...

    在android应用程序的开发过程中,相信我们很多人都想把应用的交互做的比较绚丽,比如让界面切换平滑的滚动,还有热度灰常高的伪3D等界面效果,通常情况下,系统提供的应用在特效这方面只能为我们提供简单的 ...

  8. Android 自定义 HorizontalScrollView 横向滑动效果

    自从Gallery被谷歌废弃以后,Google推荐使用ViewPager和HorizontalScrollView来实现Gallery的效果.的确HorizontalScrollView可以实现Gal ...

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

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

最新文章

  1. python线程只能启动一次_python多线程只能运行一个线程的问题
  2. 进入编辑模式、vim命令模式、vim实践
  3. NDK,动态链接库,JNI
  4. 右键删除选中的行总提示rowIndex
  5. 激励员工的首席执行官以及他们的秘诀
  6. STM32中常用的C语言知识点,开始复习!
  7. Shell脚本之一 Shell脚本简介
  8. xss挖掘思路分享_新手指南 | permeate靶场漏洞挖掘思路分享
  9. Java:final和内部类
  10. 用JS 输出 正三角形
  11. 干掉hao123恶意植入浏览器
  12. ECMAScript 是什么?
  13. 纯jquery 前端导入 Excel数据 减少服务端压力
  14. 2021中国开源码力榜启动,寻找开源世界的超级玛丽
  15. 类的访问权限-public、private、protected
  16. flex中换行符的使用
  17. 记一次磕磕绊绊的组建跨区卷过程
  18. SASO认证辅导,没有SASO证书的产品会被沙特港口海关拒绝入境
  19. app如何增加推广功能 java_Java Web app如何实现这个功能蹦?诚心求指教。
  20. Revit 2019 64位安装教程【附软件及注册机下载地址】

热门文章

  1. linux系统每月定时重启,linux系统定时重启.doc
  2. python生成相似句子_4种方法计算句子相似度
  3. Unity SRP自定义渲染管线 -- 3.Lights
  4. Sublime Text官方文档 中英文版本
  5. 人生哲理---你值得借鉴
  6. RESTful API概述
  7. javascript . 05 json的组成、for...in 遍历对象、简单数据类型与复杂数据类型的传值与传址、内置对象...
  8. C++学习笔记(五)--指针、NULL、引用
  9. 大话设计模式之策略模式
  10. 【起航计划 011】2015 起航计划 Android APIDemo的魔鬼步伐 10 App-Activity-Reorder Activities 后退栈 Intent FLAG...