android自定义布局实现优惠券效果

最近需要实现一个凹凸效果的拟物化优惠券效果,我一看,本来想用.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/253143.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

邮件实现详解(四)------JavaMail 发送(带图片和附件)和接收邮件

好了&#xff0c;进入这个系列教程最主要的步骤了&#xff0c;前面邮件的理论知识我们都了解了&#xff0c;那么这篇博客我们将用代码完成邮件的发送。这在实际项目中应用的非常广泛&#xff0c;比如注册需要发送邮件进行账号激活&#xff0c;再比如OA项目中利用邮件进行任务提…

运放搭建电压电流转换电路分析

如下图电路&#xff0c;电流可以转换成电压&#xff0c;电压也可以转换成电流&#xff1b; 根据虚断&#xff1a;(Vi–V1)/R2 (V1–V4)/R6 &#xff08;a&#xff09; 同理 (V3–V2)/R5V2/R4 &#xff08;b&#xff09; 根据虚短&#xff1a; V1V2 &#xff08;c&#xff09…

centos7装完chrome无法使用yum问题解决

2019独角兽企业重金招聘Python工程师标准>>> 续前文装好chrome后&#xff0c;yum居然用不了&#xff0c;提示错误“Basic XLib functionality test failed!” 呵呵。。。呵呵了.... 【题外话~个人真心觉得pythonseleniumchrome在linux环境下开发和使用 简直蛋疼无比…

实验二第二部分

第二部分 FTP协议分析 1. 两个同学一组&#xff0c;A和B。 2.A同学架设FTP服务器&#xff0c;并设置用户名和密码&#xff0c;例如gao / gao 3.B同学在机器中安装Wireshark&#xff0c;并将其打开&#xff1b;之后用用户名和密码登陆A同学的FTP服务器&#xff0c;并上传一张图片…

运放搭建的跟随电路作用与分析

电压跟随器&#xff0c;顾名思义就是输出电压与输入电压是相同的&#xff0c;就是说电压跟随器的电压放大倍数恒小于且接近1。 电压跟随器的显著特点就是&#xff0c;输入阻抗高&#xff0c;而输出阻抗低。 根据其显著特点&#xff0c;常见的作用如下&#xff1a; 1- 缓冲 在…

Spring Boot(十二)单元测试JUnit

一、介绍 JUnit是一款优秀的开源Java单元测试框架&#xff0c;也是目前使用率最高最流行的测试框架&#xff0c;开发工具Eclipse和IDEA对JUnit都有很好的支持&#xff0c;JUnit主要用于白盒测试和回归测试。 白盒测试&#xff1a;把测试对象看作一个打开的盒子&#xff0c;程序…

介绍TCP/udp比较好的博客

http://blog.csdn.net/nana_93/article/details/8743525

Kubernetes容器上下文环境

目录贴&#xff1a;Kubernetes学习系列 下面我们将主要介绍运行在Kubernetes集群中的容器所能够感知到的上下文环境&#xff0c;以及容器是如何获知这些信息的。 首先&#xff0c;Kubernetes提供了一个能够让容器感知到集群中正在发生的事情的方法&#xff1a;环境变量。作为容…

Shell-脚本只能运行1次

用空文件进行判断 pathpwd if [ -f ${path}/.runned ]; then {echo "This script can only execute once! You have runned it!"exit } elsetouch ${path}/.runned fi 转载于:https://www.cnblogs.com/music378/p/7677648.html

运放电压跟随电路应用

电压跟随器的显著特点&#xff1a;输入阻抗高&#xff0c;输出阻抗低。 如下所示为利用放大器搭建的电压跟随电路&#xff0c;方便测量电压大小&#xff1a; 此电路目的是测量电池电压&#xff0c;电池电压范围&#xff08;3~4.2V&#xff09;分压后最大电压为2.1V 属于3.3V电…

Mac与Phy组成原理的简单分析

Mac与Phy组成原理的简单分析 2011-12-28 15:30:43 //http://blog.chinaunix.net/uid-20528014-id-3050217.html 本文乃fireaxe原创&#xff0c;使用GPL发布&#xff0c;可以自由拷贝&#xff0c;转载。但转载请保持文档的完整性&#xff0c;并注明原作者及原链接。内容可任意使…

[BZOJ3994][SDOI2015]约数个数和

3994: [SDOI2015]约数个数和 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 1104 Solved: 762 [Submit][Status][Discuss]Description 设d(x)为x的约数个数&#xff0c;给定N、M&#xff0c;求 Input 输入文件包含多组测试数据。 第一行&#xff0c;一个整数T&#xff0…

月蚀动漫获快看漫画600万元A轮战略投资,走国漫精品化路线

11月5日消息&#xff0c;月蚀动漫宣布获得快看漫画600万元A轮战略投资。 据了解&#xff0c;月蚀动漫曾于2017年1月获得原力创投的百万级种子轮投资&#xff0c;2018年1月获得英诺天使基金的百万级天使轮投资。 据月蚀动漫创始人贺小桐透露&#xff0c;团队能在行业寒冬期获得…

大力智能台灯T6 结构拆解

近几年教育硬件产品层出不穷&#xff0c;教育硬件赛道布局时间较长的有网易、讯飞、步步高系等公司&#xff0c;2020年10月&#xff0c;字节跳动旗下大力教育经过两年多的调研和研发&#xff0c;高调推出首款智能硬件产品“大力智能作业台灯” T5。 上市一年取得不错的销售成绩…

C++静态库与动态库

http://www.cnblogs.com/skynet/p/3372855.html

第5章 IDA Pro

5.1 加载一个可执行文件 默认情况下IDA Pro的反汇编代码中不包含PE头或资源节&#xff0c;可以手动指定加载。 5.2 IDA Pro接口 5.2.1 反汇编窗口模式 二进制模式/图形模式&#xff1a; 图形模式&#xff1a;红色表示一个条件跳转没有被采用&#xff0c;绿色表示这个条件跳转被…

树链剖分(模板)

luogu题库 题目描述 如题&#xff0c;已知一棵包含N个结点的树&#xff08;连通且无环&#xff09;&#xff0c;每个节点上包含一个数值&#xff0c;需要支持以下操作&#xff1a; 操作1&#xff1a; 格式&#xff1a; 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上…

定制或外购适配器规格需求列表

输入特性例如输入电压180~264VAC 200~264VAC输入频率47~63Hz输入电流0.7A Max功率因素&#xff1e;0.47 10W220VAC浪涌电流&#xff1c;60A电源效率&#xff1e;81.26%空载功耗0.2W 输出特性例如输出电压11.4~12.6V DC输出电流1.75A纹波要求&#xff1c;120mV 负载调整率5%线性…

使用 typescript ,提升 vue 项目的开发体验(1)

此文已由作者张汉锐授权网易云社区发布。欢迎访问网易云社区&#xff0c;了解更多网易技术产品运营经验。前言&#xff1a;对于我们而言&#xff0c;typescript 更像一个工具官方指南从 vue2.5 之后&#xff0c;vue 对 ts 有更好的支持。根据官方文档&#xff0c;vue 结合 type…

Linux进程间通信——使用共享内存

//本文转载http://blog.csdn.net/ljianhui/article/details/10253345下面将讲解进程间通信的另一种方式&#xff0c;使用共享内存。一、什么是共享内存顾名思义&#xff0c;共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递…