热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:深入解析Android自定义控件——Button的72种变形技巧

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Android自定义控件系列—Button七十二变相关的知识,希望对你有一定的参考价值。 转载请注明出处:http://www.cnblogs.com

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Android自定义控件系列—Button七十二变相关的知识,希望对你有一定的参考价值。



转载请注明出处:http://www.cnblogs.com/landptf/p/6290791.html

忙了一段时间,终于有时间整理整理之前所用到的一些知识,分享给大家,希望给同学们有些帮助,同时也是对自己的知识有个巩固的过程。

android的开发中比较常用的控件就是Button了,但是我们平时使用Button时是怎样来设置按下和抬起显示不同的效果呢?我想一般的实现方式就是定义一个selector的xml文件,然后在里面根据不同的state来设置不同的图片,但是当Button控件非常多的时候,就要写对应数量的xml文件,导致大码非常臃肿。

今天我们换种方式来改变这个样式,只需要两行代码即可实现按下的效果,同时支持圆角和圆形的按钮的样式。先看下效果图,这是我写的一个demo

 

接下来讲一下主要代码: 
第一步 自定义属性 
在res/values/目录下新建attrs.xml文件


1 xml version="1.0" encoding="utf-8"?>
2 <resources>
3
4 <attr name="backColor" format="color" />
5 <attr name="backColorPress" format="color" />
6 <attr name="backGroundImage" format="reference" />
7 <attr name="backGroundImagePress" format="reference" />
8 <attr name="textColor" format="color" />
9 <attr name="textColorPress" format="color" />
10
11 <declare-styleable name="buttonM">
12 <attr name="backColor" />
13 <attr name="backColorPress" />
14 <attr name="backGroundImage" />
15 <attr name="backGroundImagePress" />
16 <attr name="textColor" />
17 <attr name="textColorPress" />
18 <attr name="fillet" format="boolean" />
19 <attr name="radius" format="float" />
20 <attr name="shape">
21 <enum name="rectangle" value="0" />
22 <enum name="oval" value="1" />
23 <enum name="line" value="2" />
24 <enum name="ring" value="3" />
25 attr>
26 declare-styleable>
27
28 resources>

具体属性的含义在java代码中都有描述 
第二步 创建ButtonM类使其继承Button,代码如下:


1 package com.landptf.view;
2
3 import android.content.Context;
4 import android.content.res.ColorStateList;
5 import android.content.res.TypedArray;
6 import android.graphics.drawable.Drawable;
7 import android.graphics.drawable.GradientDrawable;
8 import android.util.AttributeSet;
9 import android.view.MotionEvent;
10 import android.view.View;
11 import android.widget.Button;
12
13 import com.landptf.R;
14
15 /**
16 * Created by landptf on 2016/10/25.
17 * 自定义Button,支持圆角矩形,圆形按钮等样式,可通过配置文件改变按下后的样式
18 * 若通过代码设置圆角或者圆形,需要先调用setFillet方法将fillet设置为true
19 */
20 public class ButtonM extends Button {
21 private static String TAG = "ButtonM";
22 /**
23 * 按钮的背景色
24 */
25 private int backColor = 0;
26 /**
27 * 按钮被按下时的背景色
28 */
29 private int backColorPress = 0;
30 /**
31 * 按钮的背景图片
32 */
33 private Drawable backGroundDrawable = null;
34 /**
35 * 按钮被按下时显示的背景图片
36 */
37 private Drawable backGroundDrawablePress = null;
38 /**
39 * 按钮文字的颜色
40 */
41 private ColorStateList textColor = null;
42 /**
43 * 按钮被按下时文字的颜色
44 */
45 private ColorStateList textColorPress = null;
46 private GradientDrawable gradientDrawable = null;
47 /**
48 * 是否设置圆角或者圆形等样式
49 */
50 private boolean fillet = false;
51 /**
52 * 标示onTouch方法的返回值,用来解决onClick和onTouch冲突问题
53 */
54 private boolean isCost = true;
55
56 public ButtonM(Context context) {
57 super(context, null);
58 }
59
60 public ButtonM(Context context, AttributeSet attrs) {
61 this(context, attrs, 0);
62 }
63
64 public ButtonM(Context context, AttributeSet attrs, int defStyle) {
65 super(context, attrs, defStyle);
66 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.buttonM, defStyle, 0);
67 if (a != null) {
68 //设置背景色
69 ColorStateList colorList = a.getColorStateList(R.styleable.buttonM_backColor);
70 if (colorList != null) {
71 backColor = colorList.getColorForState(getDrawableState(), 0);
72 if (backColor != 0) {
73 setBackgroundColor(backColor);
74 }
75 }
76 //记录按钮被按下时的背景色
77 ColorStateList colorListPress = a.getColorStateList(R.styleable.buttonM_backColorPress);
78 if (colorListPress != null){
79 backColorPress = colorListPress.getColorForState(getDrawableState(), 0);
80 }
81 //设置背景图片,若backColor与backGroundDrawable同时存在,则backGroundDrawable将覆盖backColor
82 backGroundDrawable = a.getDrawable(R.styleable.buttonM_backGroundImage);
83 if (backGroundDrawable != null){
84 setBackgroundDrawable(backGroundDrawable);
85 }
86 //记录按钮被按下时的背景图片
87 backGroundDrawablePress = a.getDrawable(R.styleable.buttonM_backGroundImagePress);
88 //设置文字的颜色
89 textColor = a.getColorStateList(R.styleable.buttonM_textColor);
90 if (textColor != null){
91 setTextColor(textColor);
92 }
93 //记录按钮被按下时文字的颜色
94 textColorPress = a.getColorStateList(R.styleable.buttonM_textColorPress);
95 //设置圆角或圆形等样式的背景色
96 fillet = a.getBoolean(R.styleable.buttonM_fillet, false);
97 if (fillet){
98 getGradientDrawable();
99 if (backColor != 0) {
100 gradientDrawable.setColor(backColor);
101 setBackgroundDrawable(gradientDrawable);
102 }
103 }
104 //设置圆角矩形的角度,fillet为true时才生效
105 float radius = a.getFloat(R.styleable.buttonM_radius, 0);
106 if (fillet && radius != 0){
107 setRadius(radius);
108 }
109 //设置按钮形状,fillet为true时才生效
110 int shape = a.getInteger(R.styleable.buttonM_shape, 0);
111 if (fillet && shape != 0) {
112 setShape(shape);
113 }
114 a.recycle();
115 }
116 setOnTouchListener(new OnTouchListener() {
117 @Override
118 public boolean onTouch(View arg0, MotionEvent event) {
119 //根据touch事件设置按下抬起的样式
120 return setTouchStyle(event.getAction());
121 }
122 });
123 }
124
125 /**
126 * 根据按下或者抬起来改变背景和文字样式
127 * @param state
128 * @return isCost
129 * 为解决onTouch和onClick冲突的问题
130 * 根据事件分发机制,如果onTouch返回true,则不响应onClick事件
131 * 因此采用isCost标识位,当用户设置了onClickListener则onTouch返回false
132 */
133 private boolean setTouchStyle(int state){
134 if (state == MotionEvent.ACTION_DOWN) {
135 if (backColorPress != 0) {
136 if (fillet){
137 gradientDrawable.setColor(backColorPress);
138 setBackgroundDrawable(gradientDrawable);
139 }else {
140 setBackgroundColor(backColorPress);
141 }
142 }
143 if (backGroundDrawablePress != null) {
144 setBackgroundDrawable(backGroundDrawablePress);
145 }
146 if (textColorPress != null) {
147 setTextColor(textColorPress);
148 }
149 }
150 if (state == MotionEvent.ACTION_UP) {
151 if (backColor != 0) {
152 if (fillet){
153 gradientDrawable.setColor(backColor);
154 setBackgroundDrawable(gradientDrawable);
155 }else {
156 setBackgroundColor(backColor);
157 }
158 }
159 if (backGroundDrawable != null) {
160 setBackgroundDrawable(backGroundDrawable);
161 }
162 if (textColor != null) {
163 setTextColor(textColor);
164 }
165 }
166 return isCost;
167 }
168
169 /**
170 * 重写setOnClickListener方法,解决onTouch和onClick冲突问题
171 * @param l
172 */
173 @Override
174 public void setOnClickListener(OnClickListener l) {
175 super.setOnClickListener(l);
176 isCost = false;
177 }
178
179 /**
180 * 设置按钮的背景色
181 * @param backColor
182 */
183 public void setBackColor(int backColor) {
184 this.backColor = backColor;
185 if (fillet){
186 gradientDrawable.setColor(backColor);
187 setBackgroundDrawable(gradientDrawable);
188 }else {
189 setBackgroundColor(backColor);
190 }
191 }
192
193 /**
194 * 设置按钮被按下时的背景色
195 * @param backColorPress
196 */
197 public void setBackColorPress(int backColorPress) {
198 this.backColorPress = backColorPress;
199 }
200
201 /**
202 * 设置按钮的背景图片
203 * @param backGroundDrawable
204 */
205 public void setBackGroundDrawable(Drawable backGroundDrawable) {
206 this.backGroundDrawable = backGroundDrawable;
207 setBackgroundDrawable(backGroundDrawable);
208 }
209
210 /**
211 * 设置按钮被按下时的背景图片
212 * @param backGroundDrawablePress
213 */
214 public void setBackGroundDrawablePress(Drawable backGroundDrawablePress) {
215 this.backGroundDrawablePress = backGroundDrawablePress;
216 }
217
218 /**
219 * 设置文字的颜色
220 * @param textColor
221 */
222 public void setTextColor(int textColor) {
223 if (textColor == 0) return;
224 this.textColor = ColorStateList.valueOf(textColor);
225 //此处应加super关键字,调用父类的setTextColor方法,否则会造成递归导致内存溢出
226 super.setTextColor(this.textColor);
227 }
228
229 /**
230 * 设置按钮被按下时文字的颜色
231 * @param textColorPress
232 */
233 public void setTextColorPress(int textColorPress) {
234 if (textColorPress == 0) return;
235 this.textColorPress = ColorStateList.valueOf(textColorPress);
236 }
237
238 /**
239 * 设置按钮是否设置圆角或者圆形等样式
240 * @param fillet
241 */
242 public void setFillet(boolean fillet){
243 this.fillet = fillet;
244 getGradientDrawable();
245 }
246
247 /**
248 * 设置圆角按钮的角度
249 * @param radius
250 */
251 public void setRadius(float radius){
252 if (!fillet) return;
253 getGradientDrawable();
254 gradientDrawable.setCornerRadius(radius);
255 setBackgroundDrawable(gradientDrawable);
256 }
257
258 /**
259 * 设置按钮的形状
260 * @param shape
261 */
262 public void setShape(int shape){
263 if (!fillet) return;
264 getGradientDrawable();
265 gradientDrawable.setShape(shape);
266 setBackgroundDrawable(gradientDrawable);
267 }
268
269 private void getGradientDrawable() {
270 if (gradientDrawable == null){
271 gradientDrawable = new GradientDrawable();
272 }
273 }
274
275 }

注释基本上写的比较详细,下面主要说一下这里面涉及的一些知识点 
1 关于onTouch返回值问题,如果返回true表示要消费该点击事件,后续的所有事件都交给他处理,同时onTouchEvent将不会执行,因此onClick也得不到执行,在这里通过重写setOnClickListener设置变量来改变返回值。具体关于View的事件分发机制可以查阅有关文档,网上很多这方面的教程。

2 如果想要通过java代码来设置圆角或者圆形时,必须先设置setFillet(true),然后再设置背景色,形状或者角度等参数。通过xml文件则无限制

最后讲一下怎么使用,这里以设置圆角矩形为例,分别通过xml和java代码实现,其他的可参考源码。

1 xml


1 <com.landptf.view.ButtonM
2 android:id="@+id/btm_radius_color_xml"
3 android:layout_width="0dp"
4 android:layout_height="50dp"
5 android:layout_weight="1"
6 android:gravity="center"
7 android:text="点击改变背景色"
8 landptf:backColor="#ff3300"
9 landptf:backColorPress="#ff33ff"
10 landptf:fillet="true"
11 landptf:radius="30"
12 landptf:textColor="@android:color/white" />

2 java


1 ButtonM btmRadiusColorJava = (ButtonM) findViewById(R.id.btm_radius_color_java);
2 if (btmRadiusColorJava != null) {
3 btmRadiusColorJava.setFillet(true);
4 btmRadiusColorJava.setRadius(30);
5 btmRadiusColorJava.setTextColor(Color.parseColor("#ffffff"));
6 btmRadiusColorJava.setBackColor(Color.parseColor("#ff3300"));
7 btmRadiusColorJava.setBackColorPress(Color.parseColor("#ff33ff"));
8 btmRadiusColorJava.setOnClickListener(new View.OnClickListener() {
9 @Override
10 public void onClick(View v) {
11 Toast.makeText(ButtonMTestActivity.this, "java代码实现", Toast.LENGTH_SHORT).show();
12 }
13 });
14 }

代码已托管到开源中国的码云上,欢迎下载,地址:https://git.oschina.net/landptf/landptf.git



推荐阅读
  • 本文详细介绍了 jQuery 的入门知识与实战应用,首先讲解了如何引入 jQuery 库及入口函数的使用方法,为初学者提供了清晰的操作指南。此外,还深入探讨了 jQuery 在实际项目中的多种应用场景,包括 DOM 操作、事件处理和 AJAX 请求等,帮助读者全面掌握 jQuery 的核心功能与技巧。 ... [详细]
  • Java Web开发中的JSP:三大指令、九大隐式对象与动作标签详解
    在Java Web开发中,JSP(Java Server Pages)是一种重要的技术,用于构建动态网页。本文详细介绍了JSP的三大指令、九大隐式对象以及动作标签。三大指令包括页面指令、包含指令和标签库指令,它们分别用于设置页面属性、引入其他文件和定义自定义标签。九大隐式对象则涵盖了请求、响应、会话、应用上下文等关键组件,为开发者提供了便捷的操作接口。动作标签则通过预定义的动作来简化页面逻辑,提高开发效率。这些内容对于理解和掌握JSP技术具有重要意义。 ... [详细]
  • 深入解析 Android 选择器与形状绘制技术
    本文深入探讨了 Android 中选择器(Selector)与形状绘制(Shape Drawing)技术的应用与实现。重点分析了 `Selector` 的 `item` 元素,其中包括 `android:drawable` 属性的使用方法及其在不同状态下的表现。此外,还详细介绍了如何通过 XML 定义复杂的形状和渐变效果,以提升 UI 设计的灵活性和美观性。 ... [详细]
  • 本文介绍了如何通过掌握 IScroll 技巧来实现流畅的上拉加载和下拉刷新功能。首先,需要按正确的顺序引入相关文件:1. Zepto;2. iScroll.js;3. scroll-probe.js。此外,还提供了完整的代码示例,可在 GitHub 仓库中查看。通过这些步骤,开发者可以轻松实现高效、流畅的滚动效果,提升用户体验。 ... [详细]
  • 可转债数据智能抓取与分析平台优化
    本项目旨在优化可转债数据的智能抓取与分析平台。通过爬取集思录上的可转债信息(排除已发布赎回的债券),并结合安道全教授提出的三条安全线投资策略,新增了建仓线、加仓线和重仓线,以提供更精准的投资建议。 ... [详细]
  • Spring框架中的面向切面编程(AOP)技术详解
    面向切面编程(AOP)是Spring框架中的关键技术之一,它通过将横切关注点从业务逻辑中分离出来,实现了代码的模块化和重用。AOP的核心思想是将程序运行过程中需要多次处理的功能(如日志记录、事务管理等)封装成独立的模块,即切面,并在特定的连接点(如方法调用)动态地应用这些切面。这种方式不仅提高了代码的可维护性和可读性,还简化了业务逻辑的实现。Spring AOP利用代理机制,在不修改原有代码的基础上,实现了对目标对象的增强。 ... [详细]
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • 技术分享:深入解析GestureDetector手势识别机制
    技术分享:深入解析GestureDetector手势识别机制 ... [详细]
  • 探索聚类分析中的K-Means与DBSCAN算法及其应用
    聚类分析是一种用于解决样本或特征分类问题的统计分析方法,也是数据挖掘领域的重要算法之一。本文主要探讨了K-Means和DBSCAN两种聚类算法的原理及其应用场景。K-Means算法通过迭代优化簇中心来实现数据点的划分,适用于球形分布的数据集;而DBSCAN算法则基于密度进行聚类,能够有效识别任意形状的簇,并且对噪声数据具有较好的鲁棒性。通过对这两种算法的对比分析,本文旨在为实际应用中选择合适的聚类方法提供参考。 ... [详细]
  • iOS开发中MVC架构模式的深入解析(第一部分)
    在iOS开发中,MVC架构模式是常用的设计模式之一。本文将深入解析MVC架构的第一部分,重点介绍View组件。View组件继承自UIView,主要负责内容的展示(如UILabel等视图类)和用户输入的处理(如UIButton等控件类)。通过详细的代码示例和实际应用,帮助开发者更好地理解和掌握View在MVC架构中的作用和实现方式。 ... [详细]
  • 通过整合JavaFX与Swing,我们成功地将现有的Swing应用程序组件进行了现代化改造。此次升级不仅提升了用户界面的美观性和交互性,还确保了与原有Swing应用程序的无缝集成,为开发高质量的Java桌面应用提供了坚实的基础。 ... [详细]
  • Spring框架入门指南:专为新手打造的详细学习笔记
    Spring框架是Java Web开发中广泛应用的轻量级应用框架,以其卓越的功能和出色的性能赢得了广大开发者的青睐。本文为初学者提供了详尽的学习指南,涵盖基础概念、核心组件及实际应用案例,帮助新手快速掌握Spring框架的核心技术与实践技巧。 ... [详细]
  • 深入解析Tomcat:开发者的实用指南
    深入解析Tomcat:开发者的实用指南 ... [详细]
  • 本文详细探讨了代码中 `position` 属性的使用方法及其常见问题,并提出了多种有效的解决方案。通过实例分析,文章不仅解释了 `position` 属性的不同值(如 `static`、`relative`、`absolute` 和 `fixed`)在不同场景下的应用,还讨论了其对布局和定位的影响。此外,文章还提供了一些实用的调试技巧和最佳实践,帮助开发者更好地理解和应用这一重要 CSS 属性。 ... [详细]
  • 如何构建基于Spring MVC框架的Java Web应用项目
    在构建基于Spring MVC框架的Java Web应用项目时,首先应创建一个新的动态Web项目。接着,需将必要的JAR包导入至WebContent/WEB-INF/lib目录下,确保包括Spring核心库及相关依赖。如遇缺失的JAR包,可向社区求助或通过Maven等工具自动下载。正确配置后,即可开始搭建应用结构与功能模块。 ... [详细]
author-avatar
_i逗比_985
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有