android自定义控件(1)-自定义控件属性
那么还是针对我们之前写的自定义控件:开关按钮为例来说,在之前的基础上,我们来看看有哪些属性是可以自定义的:按钮的背景图片,按钮的滑块图片,和按钮的状态(是开还是关),实际上都应该是可以在xml文件中直接定义的。
不妨先来看看之前我们在代码中不依靠自定义属性的时候,是如何写的,我们可以在initView方法中找到这样几行代码:
backgroundBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.switch_background); slideButton = BitmapFactory.decodeResource(getResources(),
R.drawable.slide_button); currentState=false;
会发现,我们是直接引用的资源文件,而不是在布局xml文件中使用的定义属性的方式,下面我们一步步来看看要怎么样做才可以定义使用上自定义属性:
第一步:在res/values文件夹中添加attrs.xml文件
实际上,这个文件名并不一定要写成attrs.xml,但是按照android源码的写法并且也便于别人查看代码的时候明确这个文件的用意,还是写成attrs.xml。
下面要如何写呢,我们还是可以参看一下安卓的源码:打开源码文件夹下\frameworks\base\core\res\res\values\attrs.xml文件,我们会发现这里面定义了很多attr的标签,里面不乏一些我们常见的属性:
<attr name="layout_width" format="dimension">
等等,在layout_width这个标签上面我们还可以发现一个
<declare-styleable name="ViewGroup_Layout">
declare-styleable标签的里包含了很多根ViewGruop相关的属性。
而在这个attrs.xml文件的最外面,是一个<resources>的标签
到这里,我们基本上就明白了一个attrs.xml文件的结构了:
首先要一个<resources>的父标签,然后里面可以包含一个declare-styleable的标签,在这个标签里面我们再定义出三个attr 标签,分别代表我们需要定义的三个属性:按钮的背景图片,按钮的滑块图片,和按钮的状态;那么剩下的一个问题就是attr标签中的format代表什么意思。实际上format代表的是这条属性的值的类型:
1.reference:参考指定Theme中资源ID,这个类型意思就是你传的值可以是引用资源
2.string:字符串,如果你想别人既能直接写值也可以用类似"@string/test"引用资源的方式,可以写成format="string|reference"
3.Color:颜色
4.boolean:布尔值
5.dimension:尺寸值
6.float:浮点型
7.integer:整型
8.fraction:百分数
9.enum:枚举 ,如果你提供的属性只能让别人选择,不能随便传入,就可以写成这样
<attr name="language">
<enum name="china" value="1"/>
<enum name="English" value="2"/>
</attr>
10.flag:位或运算
declare-styleable子元素:
定义一个styleable对象,每个styleable对象就是一组attr属性的集合 注意:这里的name属性并不是一定要和自定义类名相同,只是为了好区分对应类的属性而已
注意:上面的属性资源文件定义了该属性之后,至于到底是哪个自定义View组件中来使用该属性,该属性到底能发挥什么作用, 就不归该属性资源文件管了,也就是说这个属性资源文件是个公共的,大家都可以用,但是为了方便管理,一般都是一个自定义View里的属性写成一个declare-styleable集合.属性资源所定义的属性到底可以返回什么作用,取决于自定义组件的代码实现
在这里,我们的attrs.xml文件写成下面这样:
<?xml version="1.0" encoding="utf-8"?>
<resources> <declare-styleable name="DJSwitch"> <attr name="current_state" format="boolean"/>
<attr name="backgroundImage" format="reference"/>
<attr name="slideImage" format="reference"/> </declare-styleable> </resources>
第二步:在自定义控件的类中拿到attrs.xml文件中定义的属性的对应的值,然后赋值给我们需要设置的变量,在这里就是 背景图片,滑块图片和开关状态 这三个值。
要如何做呢?我们先将上面给出的
backgroundBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.switch_background); slideButton = BitmapFactory.decodeResource(getResources(),
R.drawable.slide_button); currentState=false;
这三句注释掉,然后换成下面的代码
/**
* 初始化View
*/
private void initView(Context context, AttributeSet attrs) {
/*
* 从资源库中加载一个image对象
* ios UIImage *backgroundImage = [UIImage imageNamed:@"app_switch_bg"];
* 也就是说,android里面的图像实体bitmap,可以当成是ios中的UIImage
* 区别在于,ios中UIImage可以通过类方法来获取,android里面则是通过工厂方法来实现
*/
/*switch_bg_img = BitmapFactory.decodeResource(getResources(), R.drawable.app_switch_bg);
switch_btn_img = BitmapFactory.decodeResource(getResources(), R.drawable.app_switch_btn);
*/ // 可以把这个TypedArray看成是一个包含了DJSwitch属性集合的HashMap
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.DJSwitch);
// 获取该集合中共有多少个index
int indexCount = typedArray.getIndexCount(); for (int i = 0; i < indexCount; i++) {
int id = typedArray.getIndex(i);
switch (id) {
case R.styleable.DJSwitch_backgroundImage:
switch_bg_img = ((BitmapDrawable)typedArray.getDrawable(id)).getBitmap();
break;
case R.styleable.DJSwitch_slideImage:
switch_btn_img = ((BitmapDrawable)typedArray.getDrawable(id)).getBitmap();
break;
case R.styleable.DJSwitch_current_state:
currentState = typedArray.getBoolean(id, false);
break;
default:
break;
}
} switchBtnMaxSlideDistance = switch_bg_img.getWidth() - switch_btn_img.getWidth();
if (currentState) {
switchBtnX = switchBtnMaxSlideDistance;
} else {
switchBtnX = 0;
}
typedArray.recycle();
// 添加监听
setOnClickListener(new MyOnSwitchClickListener()); // 可以理解为ios中的addTarget方法,或addGestureRecognizer
}
注释上面已经写得很清楚了,TypedArray会把XML文件所引用的自定义属性和值保存在一个Map表中,因此我们可以根据该Map的键(即:属性的ID)取出该属性对应的值。
第三步:在布局文件中使用自定义属性,并设置属性值:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:alex="http://schemas.android.com/apk/res/com.example.test"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
> <!-- 为了清楚的看见该View的大小及位置,给其定义背景 -->
<com.example.test.view.DJSwitch
android:id="@+id/sw_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ff0000"
android:layout_centerInParent="true"
alex:current_state="false"
alex:backgroundImage="@drawable/app_switch_bg"
alex:slideImage="@drawable/app_switch_btn"
/> </RelativeLayout>
在上面的代码,我们发现我们写成了alex:这样的标头,这个实际上是命名空间的简写(默认是app),所以我们必须要添加一个命名空间,参看一下Android的命名空间是如何写的:
xmlns:android="http://schemas.android.com/apk/res/android"
在这里xmlns:android里面的android,是可以变化的,这里我们就改为alex,然后对于http://schemas.android.com/apk/res/android这个部分,最后的android也要改的,这里必须改成整个应用的包名,我们可以去清单文件中查找,这里是com.example.togglebutton,所以整个写下来就是:xmlns:alex="http://schemas.android.com/apk/res/com.example.test"
于是这里一个完整的布局文件写为:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:alex="http://schemas.android.com/apk/res/com.example.test"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
> <!-- 为了清楚的看见该View的大小及位置,给其定义背景 -->
<com.example.test.view.DJSwitch
android:id="@+id/sw_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ff0000"
android:layout_centerInParent="true"
alex:current_state="false"
alex:backgroundImage="@drawable/app_switch_bg"
alex:slideImage="@drawable/app_switch_btn"
/> </RelativeLayout>
至此,在XML自定义按钮属性的基本步骤已经全部完毕了。不过如果我们想同时在代码中设置该按钮的属性该如何做呢?,很简单,在代码中为这三个自定义的按钮属性分别建立一个成员变量。
DJSwitch.java
/**
* 标识当前按钮状态
* 类似于iOS中.h文件里声明property 为BOOL类型的属性
*/
private boolean currentState;
/** 滑动按钮背景 */
private Bitmap switch_bg_img;
/** 滑动按钮滑块 */
private Bitmap switch_btn_img;
同时提供三个接口方法
/**
* 设置当前按钮开关状态
* @param isOpen true: 开,false: 关
*/
public void setCurrentSwitchState(boolean isOpen) {
this.currentState = isOpen;
if (isOpen) {
switchBtnX = switchBtnMaxSlideDistance;
} else {
switchBtnX = 0;
}
invalidate();
} /**
* 设置当前按钮背景图片
* @param resId 资源ID
*/
public void setBackgroundImage(int resId) {
switch_bg_img = BitmapFactory.decodeResource(getResources(), resId);
// 因背景图片更改,须同时更新滑块最大移动距离
switchBtnMaxSlideDistance = switch_bg_img.getWidth() - switch_btn_img.getWidth();
invalidate(); // 相当于iOS中setNeedDisplay方法
} /**
* 设置滑动按钮图片
* @param resId 资源ID
*/
public void setSlideBtnImage(int resId) {
switch_btn_img = BitmapFactory.decodeResource(getResources(), resId);
switchBtnMaxSlideDistance = switch_bg_img.getWidth() - switch_btn_img.getWidth();
invalidate();
}
MainActivity.java
package com.example.test; import com.example.test.view.DJSwitch; import android.app.Activity;
import android.os.Bundle; public class MainActivity extends Activity { private DJSwitch sw_switch; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUIView();
} private void initUIView() {
sw_switch = (DJSwitch) findViewById(R.id.sw_switch);
sw_switch.setCurrentSwitchState(true);
sw_switch.setSlideBtnImage(R.drawable.ic_launcher);
} }
最终效果:
android自定义控件(1)-自定义控件属性的更多相关文章
- Android开发技巧——自定义控件之增加状态
Android开发技巧--自定义控件之增加状态 题外话 这篇本该是上周四或上周五写的,无奈太久没写博客,前几段把我的兴头都用完了,就一拖再拖,直到今天.不想把这篇拖到下个月,所以还是先硬着头皮写了. ...
- Android开发技巧——自定义控件之使用style
Android开发技巧--自定义控件之使用style 回顾 在上一篇<Android开发技巧--自定义控件之自定义属性>中,我讲到了如何定义属性以及在自定义控件中获取这些属性的值,也提到了 ...
- Android开发技巧——自定义控件之自定义属性
Android开发技巧--自定义控件之自定义属性 掌握自定义控件是很重要的,因为通过自定义控件,能够:解决UI问题,优化布局性能,简化布局代码. 上一篇讲了如何通过xml把几个控件组织起来,并继承某个 ...
- Android开发技巧——自定义控件之组合控件
Android开发技巧--自定义控件之组合控件 我准备在接下来一段时间,写一系列有关Android自定义控件的博客,包括如何进行各种自定义,并分享一下我所知道的其中的技巧,注意点等. 还是那句老话,尽 ...
- 荐 android 如何打包自定义控件(转)
荐 android 如何打包自定义控件(转) 目录[-] 方式一:将项目打包成jar包 方式二:项目作为一个library 设计自定义的控件对android开发人员来说,是家常便饭了,但是多次做项 ...
- C#中的自定义控件中的属性、事件及一些相关特性的总结(转)
摘要: C#中的自定义控件中的属性(Property).事件(Event)及一些相关特性(Attribute)的总结 今天学习了下C#用户控件开发添加自定义属性的事件,主要参考了MSDN,总结并实 ...
- android中xml tools属性详解
第一部分 安卓开发中,在写布局代码的时候,ide可以看到布局的预览效果. 但是有些效果则必须在运行之后才能看见,比如这种情况:TextView在xml中没有设置任何字符,而是在activity中设置了 ...
- Android读取自定义View属性
Android读取自定义View属性 attrs.xml : <?xml version="1.0" encoding="utf-8"?> < ...
- android中xmlns:tools属性详解
今天读到一篇总结的非常棒的文章,写的逻辑很清晰也很实用,很少见到如此棒的文章了.就原文转发过来,我把格式给整理了一下,分享给园子里的各位朋友!好久没写博客了,就为2015年的11月留份纪念吧.希望对你 ...
- Mono for Android布局控件属性小结
1. layout_weight 用于给一个线性布局中的诸多视图的重要度赋值. 所有的视图都有一个layout_weight值,默认为零,意思是需要显示 多大的视图就占据多大的屏幕空 间.若赋一个高于 ...
随机推荐
- (原创)2. WPF中的依赖属性之二
1 依赖属性 1.1 依赖属性最终值的选用 WPF属性系统对依赖属性操作的基本步骤如下: 第一,确定Base Value,对同一个属性的赋值可能发生在很多地方.还用Button的宽度来进行举例,可能在 ...
- poj 3264 Balanced Lineup 题解
Balanced Lineup Time Limit: 5000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u Subm ...
- Win7+Qt5.6.0(64位)+msvc2015编译器 环境配置
根据“Qt简介,Qt 5.6.0-VS2015 版本安装配置图文教程”安装第二套IDE,使用Qt官方的集成开发环境 QtCreator + 微软的WinDbg调试器(内含命令行调试器为CDB)的组合. ...
- 织梦(Dedecms) 5.1 feedback_js.php 注入漏洞
漏洞版本: DEDECMS 5.1 漏洞描述: 同样是在magic_quotes_gpc=off的情况下可用 此漏洞可拿到后台管理员的帐号和加密HASH,漏洞存在文件plus/feedback_js. ...
- Orchard运用 - 理解App_Data目录结构
了解一个系统,应该基本上要了解目录结构及其组织形式.这样对于开发人员更是必备的知识,比如开发模块最终安装到哪,主题Themes是如何配置启用. 今天跟大家分享其实是个笔记记录,就是看到有一篇文章介绍A ...
- 常见文本框提示css技巧
很多时候会碰到那个的表单 一般我们做文字提醒功能时会在value处直接写上,现在总结一个比较好的方法直接上代码: html: <dl class="login_from"&g ...
- FrameWork数据权限浅析2之基于用户的配置表实现行级数据安全
在上一篇笔记中我已经说了如何利用FM自带的机制配合我们已经通过验证的用户空间的组来实现行级数据安全的控制,但是由于上一个方法存在的缺点是以后如果对该对象增加基于用户或者角色的访问权限就需要开发人员去F ...
- Android四大基本组件之 Activity
[Activity介绍] Activity 是用户接口程序,原则上它会提供给用户一个交互式的接口功能. 它是 android 应用程序的基本功能单元.Activity 本身是没有界面的.所以activ ...
- ant design pro (十一)advanced Mock 和联调
一.概述 原文地址:https://pro.ant.design/docs/mock-api-cn Mock 数据是前端开发过程中必不可少的一环,是分离前后端开发的关键链路.通过预先跟服务器端约定好的 ...
- cocos2d-x CCScrollView 源代码分析
版本号源代码来自2.x,转载请注明 另我实现了能够循环的版本号http://blog.csdn.net/u011225840/article/details/31354703 1.继承树结构 能够看出 ...