android自定义控件并添加属性的方法以及示例

简介:

安卓系统为我们提供了丰富的控件,但是在实际项目中我们仍然需要重新通过布局来实现一些效果,比如我们需要一个上面图标,下面文字的button,类似于下面这样的:

最直接的解决办法是通过将imageview和textview放在一个垂直排列的LinearLayout中,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:gravity= "center"
     android:orientation= "vertical" >
     <ImageView
         android:id= "@+id/icon_part"
         android:layout_width= "wrap_content"
         android:layout_height= "wrap_content"
         android:layout_gravity= "center"
         />
     <TextView
         android:id= "@+id/text_part"
         android:layout_width= "wrap_content"
         android:layout_height= "wrap_content"
         android:layout_gravity= "center"
         android:textColor= "#000000" />
</LinearLayout>

但是每一个button都需要这么长的代码,上面三个按钮的话就需要重复写三次,而且别人一看是个LinearLayout,不会将它button联系起来。

如果有一种办法能将上面那个布局组合成一个控件就好了。

的确是有办法的。主要有两方面的工作。

1.新建一个继承自LinearLayout的类(也可以是其他布局类,不过LinearLayout好像比较合适),然后通过inflater在这个类的构造函数中将上面的布局添加进去。

2.为了能在xml中也给这个自定义控件赋予属性来获得现实效果,比如字体大小、图标资源等,我们还需要在attrs文件中申明一些自定义属性。你可以查阅declare-styleable了解这是怎么回事。


我这里有一个已经实现了这种button效果的类FlexImageButton:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.jcodecraeer.client.widget;
import com.jcodecraeer.client.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class FlexImageButton extends LinearLayout {
     private ImageView imageView;
     private TextView textView;
     private CharSequence text;
     private Drawable drawable;
     private float textSize;
     public FlexImageButton(Context context) {
         super (context);
         // TODO Auto-generated constructor stub
     }
     public FlexImageButton(Context context, AttributeSet attrs) {
         super (context, attrs);
         // TODO Auto-generated constructor stub
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlexImageButton);
         text = a.getText(R.styleable.FlexImageButton_text);
         if (text== null ){
             text= "" ;
         }
         Drawable d = a.getDrawable(R.styleable.FlexImageButton_src);
         if (d != null ) {
             drawable=d;
         } else {
             throw new RuntimeException( "图像资源为空" );
         }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
         textSize = a.getDimension(R.styleable.FlexImageButton_textSize,12);
         String infService = Context.LAYOUT_INFLATER_SERVICE;
         LayoutInflater inflater = (LayoutInflater) context
                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         inflater.inflate(R.layout.flex_image_button_layout, this );
         imageView = (ImageView) findViewById(R.id.icon_part);
         imageView.setImageDrawable(drawable);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
         textView = (TextView) findViewById(R.id.text_part);
         textView.setTextSize((float) textSize);
         textView.setText(text);
         if (text.equals( "" )||text== null ){
             textView.setVisibility(View.GONE);
         }
         a.recycle();
     }
     public void setImageResource(int resId) {
         imageView.setImageResource(resId);
     }
     public void setTextViewText(String text) {
         textView.setText(text);
     }
}


在attrs.xml文件中我们声明一些自定义属性,这里我们希望我的FlexImageButton能拥有可以灵活设置的文字属性,字体大小属性、图标资源属性,因此我这样定义:

1
2
3
4
5
6
7
<resources>
     <declare-styleable name= "FlexImageButton" >
         <attr name= "text" format= "reference" />
         <attr name= "src" format= "reference" />
         <attr name= "textSize"  format= "dimension" />
     </declare-styleable>
</resources>


其中format="reference"表示这个属性的值类型是资源id,也就是说在使用FlexImageButton的时候我只可以用资源id来为这个属性赋值。属性值类型有那些,我在文章结尾的附录里面一一列出。



上面我们已经完成了一个自定义的控件,activity的布局文件中如下使用FlexImageButton:

1
2
3
4
5
6
7
8
9
10
11
12
13
<com.jcodecraeer.client.widget.FlexImageButton
     android:layout_height= "fill_parent"       
     android:layout_width= "50dip"
     cl:src= "@drawable/toolbar_collect"
     cl:text= "@string/collect"
     android:clickable= "true"
     android:focusable= "true"
     android:layout_marginLeft= "5dip"
     android:layout_marginRight= "5dip"
     android:contentDescription= "收藏"
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
     android:background= "@drawable/back_selector"
/>

仔细的人会注意到所有这些属性中,有两种形式。其中凡是android:开头的都是系统属性,而

1
2
cl:src= "@drawable/toolbar_collect"
cl:text= "@string/collect"

为我自定义的属性,为什么是cl:开头?

你也可以不用cl开头,但是不管你用什么开头,如果你用到了自定义属性,你都必须在activity布局文件的最开始这样声明:

1
2
3
4
<?xml version= "1.0" encoding= "utf-8" ?>
<RelativeLayout
     xmlns:android= "http://schemas.android.com/apk/res/android"

其中cl就是刚刚用到的,com.jcodecraeer.client为我的apk包名,注意是apk包名,而不是你自定义控件的在包中的路径。


附录:自定义属性的值类型:

1. reference:参考某一资源ID。

(1)属性定义:

1
2
3
<declare-styleable name= "名称" >
     <attr format= "reference" name= "background" />
</declare-styleable>

(2)属性使用:

1
2
3
4
<ImageView
     android:layout_width= "42dip"
     android:layout_height= "42dip"
     android:background= "@drawable/图片ID" />

2. color:颜色值。

(1)属性定义:

1
2
3
<declare-styleable name= "名称" >
     <attr format= "color" name= "textColor" />
</declare-styleable>

(2)属性使用:

1
2
3
4
<TextView
     android:layout_width= "42dip"
     android:layout_height= "42dip"
     android:textColor= "#00FF00" />

3. boolean:布尔值。

(1)属性定义:

1
2
3
<declare-styleable name= "名称" >
     <attr format= "boolean" name= "focusable" />
</declare-styleable>

(2)属性使用:

1
2
3
4
<Button
     android:layout_width= "42dip"
     android:layout_height= "42dip"
     android:focusable= "true" />

4. dimension:尺寸值。

(1)属性定义:

1
2
3
<declare-styleable name= "名称" >
     <attr format= "dimension" name= "layout_width" />
</declare-styleable>

(2)属性使用:

1
2
3
<Button
     android:layout_width= "42dip"
     android:layout_height= "42dip" />

5. float:浮点值。

(1)属性定义:

1
2
3
4
<declare-styleable name= "AlphaAnimation" >
     <attr format= "float" name= "fromAlpha" />
     <attr format= "float" name= "toAlpha" />
</declare-styleable>

(2)属性使用:

1
2
3
<alpha
     android:fromAlpha= "1.0"
     android:toAlpha= "0.7" />

6. integer:整型值。

(1)属性定义:

1
2
3
4
<declare-styleable name= "AnimatedRotateDrawable" >
     <attr format= "integer" name= "frameDuration" />
     <attr format= "integer" name= "framesCount" />
</declare-styleable>

(2)属性使用:

1
2
3
4
<animated-rotate
     android:frameDuration= "100"
     android:framesCount= "12"
      />

7. string:字符串。

(1)属性定义:

1
2
3
<declare-styleable name= "MapView" >
     <attr format= "string" name= "apiKey" />
</declare-styleable>

(2)属性使用:

1
2
3
4
<com.google.android.maps.MapView
     android:layout_width= "fill_parent"
     android:layout_height= "fill_parent"
     android:apiKey= "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g" />

8. fraction:百分数。

(1)属性定义:

1
2
3
4
<declare-styleable name= "RotateDrawable" >
     <attr format= "fraction" name= "pivotX" />
     <attr format= "fraction" name= "pivotY" />
</declare-styleable>

(2)属性使用:

1
2
3
4
<rotate
     android:pivotX= "200%"
     android:pivotY= "300%"
     />

9. enum:枚举值。

(1)属性定义:

1
2
3
4
5
6
<declare-styleable name= "名称" >
     <attr name= "orientation" >
         <enum name= "horizontal" value= "0" />
         <enum name= "vertical" value= "1" />
     </attr>
</declare-styleable>

(2)属性使用:

1
2
3
<LinearLayout
     android:orientation= "vertical" >
</LinearLayout>

10. flag:位或运算。

(1)属性定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<declare-styleable name= "名称" >
     <attr name= "windowSoftInputMode" >
         <flag name= "stateUnspecified" value= "0" />
         <flag name= "stateUnchanged" value= "1" />
         <flag name= "stateHidden" value= "2" />
         <flag name= "stateAlwaysHidden" value= "3" />
         <flag name= "stateVisible" value= "4" />
         <flag name= "stateAlwaysVisible" value= "5" />
         <flag name= "adjustUnspecified" value= "0x00" />
         <flag name= "adjustResize" value= "0x10" />
         <flag name= "adjustPan" value= "0x20" />
         <flag name= "adjustNothing" value= "0x30" />
     </attr>
</declare-styleable>

(2)属性使用:

1
2
3
<activity
     android:windowSoftInputMode= "stateUnspecified | stateUnchanged | stateHidden" >
</activity>

注意:属性定义时可以指定多种类型值:

(1)属性定义:

1
2
3
<declare-styleable name= "名称" >
     <attr format= "reference|color" name= "background" />
</declare-styleable>

(2)属性使用:

1
2
3
4
<ImageView
     android:layout_width= "42dip"
     android:layout_height= "42dip"
     android:background= "@drawable/图片ID|#00FF00" />

相关文章
|
29天前
|
缓存 搜索推荐 Android开发
安卓开发中的自定义控件实践
【10月更文挑战第4天】在安卓开发的海洋中,自定义控件是那片璀璨的星辰。它不仅让应用界面设计变得丰富多彩,还提升了用户体验。本文将带你探索自定义控件的核心概念、实现过程以及优化技巧,让你的应用在众多竞争者中脱颖而出。
|
3月前
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
68 2
基于Android P,自定义Android开机动画的方法
|
3月前
|
Android开发
基于android-11.0.0_r39,系统应用的手动签名方法和过程
本文介绍了基于Android 11.0.0_r39版本进行系统应用手动签名的方法和解决签名过程中遇到的错误,包括处理`no conscrypt_openjdk_jni-linux-x86_64`和`RegisterNatives failed`的问题。
149 2
|
12天前
|
缓存 Java Shell
Android 系统缓存扫描与清理方法分析
Android 系统缓存从原理探索到实现。
38 15
Android 系统缓存扫描与清理方法分析
|
14天前
|
存储 前端开发 测试技术
Android kotlin MVVM 架构简单示例入门
Android kotlin MVVM 架构简单示例入门
22 1
|
28天前
|
缓存 搜索推荐 Android开发
安卓开发中的自定义控件基础与进阶
【10月更文挑战第5天】在Android应用开发中,自定义控件是提升用户体验和界面个性化的重要手段。本文将通过浅显易懂的语言和实例,引导你了解自定义控件的基本概念、创建流程以及高级应用技巧,帮助你在开发过程中更好地掌握自定义控件的使用和优化。
33 10
|
29天前
|
前端开发 搜索推荐 Android开发
安卓开发中的自定义控件实践
【10月更文挑战第4天】在安卓开发的世界里,自定义控件如同画家的画笔,能够绘制出独一无二的界面。通过掌握自定义控件的绘制技巧,开发者可以突破系统提供的界面元素限制,创造出既符合品牌形象又提供卓越用户体验的应用。本文将引导你了解自定义控件的核心概念,并通过一个简单的例子展示如何实现一个基本的自定义控件,让你的安卓应用在视觉和交互上与众不同。
|
2月前
|
缓存 前端开发 Android开发
安卓应用开发中的自定义控件
【9月更文挑战第28天】在安卓应用开发中,自定义控件是提升用户界面和交互体验的关键。本文通过介绍如何从零开始构建一个自定义控件,旨在帮助开发者理解并掌握自定义控件的创建过程。内容将涵盖设计思路、实现方法以及性能优化,确保开发者能够有效地集成或扩展现有控件功能,打造独特且高效的用户界面。
|
2月前
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
42 2
|
2月前
|
搜索推荐 Android开发 开发者
探索安卓开发中的自定义控件
【9月更文挑战第5天】在安卓开发的海洋中,自定义控件如同一艘精致的小船,让开发者能够乘风破浪,创造出既独特又高效的用户界面。本文将带你领略自定义控件的魅力,从基础概念到实战应用,一步步深入理解并掌握这一技术。