Android初级教程初谈自定义view自定义属性
有些时候,自己要在布局文件中重复书写大量的代码来定义一个布局。这是最基本的使用,当然要掌握;但是有些场景都去对应的布局里面写对应的属性,就显得很无力。会发现,系统自带的控件无法满足我们的要求,这个时候就要考虑自定义控件。自定义view的世界,也很浩瀚,个人需要学的地方还有很多很多。自定义view,会节省开发效率,很有必要学习其基本原理和方法。接下来就对自定义view,做一个初步的认识,一步步了解封装的重要性。但是,也仅仅是一个初步,因为它实在太灵活了。
有这么一种场景,看图:
除了布局之外,还有一点。当用户点击的时候,会自动选中复选框,而且红色textview变为绿色。且改变了内容。
那就一点点的看看怎么通过自定义view和自定义属性来完成上述功能。
首先,它是显示在一个活动中的。这个活动,就定位为SettingCenterActivity,要在这个活动中加载上面的的布局。通过以前的方式来完成一下布局上的功能。就使用线性布局,冗余的代码写了出来:
定义一个activity_settingcenter.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" > <TextView
style="@style/tv_title"
android:text="设置中心" /> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" > <TextView
android:id="@+id/tv_settingcenter_autoupdate_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="自动更新设置"
android:textSize="22sp" /> <TextView
android:id="@+id/tv_settingcenter_autoupdate_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_settingcenter_autoupdate_title"
android:layout_margin="5dp"
android:text="自动更新已经关闭"
android:textSize="22sp" /> <CheckBox
android:id="@+id/cb_settingcenter_autoupdate_checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" /> <View
android:layout_below="@id/tv_settingcenter_autoupdate_content"
android:layout_width="wrap_content"
android:layout_height="2dp"
android:background="@drawable/list_devider" />
</RelativeLayout> </LinearLayout>
运行程序,已经实现了效果。但是,如果继续显示“黑名单拦截设置”设置更多的话,或者要修改每一项的参数属性值的话,就要不断的重复写代码了,这样显然浪费时间。
所以,做第一步封装:
把这个布局抽取成一个布局,item_settingcenterview.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" > <TextView
android:id="@+id/tv_settingcenter_autoupdate_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="自动更新设置"
android:textSize="22sp" /> <TextView
android:id="@+id/tv_settingcenter_autoupdate_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_settingcenter_autoupdate_title"
android:layout_margin="5dp"
android:text="自动更新已经关闭"
android:textSize="22sp" /> <CheckBox
android:id="@+id/cb_settingcenter_autoupdate_checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" /> <View
android:layout_width="wrap_content"
android:layout_height="2dp"
android:layout_below="@id/tv_settingcenter_autoupdate_content"
android:background="@drawable/list_devider" /> </RelativeLayout>
然后把第一个布局文件中的这一部分删掉,通过<include />引入进来item_settingcenterview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" > <TextView
style="@style/tv_title"
android:text="设置中心" /> <include layout="@layout/item_settingcenter_view"/>
<include layout="@layout/item_settingcenter_view"/>
<include layout="@layout/item_settingcenter_view"/> </LinearLayout>
这时发发现问题好像都解决了,一项接着一项,看似很完美。但是问题又来了,怎么修改每一项的属性值呢?好像无从下手。会想到,如果能把整个布局看成一个view,在
activity_settingcenter.xml中像类似引用textview一样就好了!其实,textview在代码中是一个类,继承自view才有了view的功能。那么我们就自己定义一个类,继承自某个容器类型的view,会不会有view的属性和功能了?答案是肯定的,因为子类使用父类功能,天经地义,子类都比父类要强大!能像使用LinearLayout一样使用自定义的view
继续改进(自定义view解决上面的一切问题)。
新建一个类SettingCenterItenView继承自LinearLayout类,加入如下功能:
package com.example.ydlmobileguard.views; import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout; public class SettingCenterItemView extends LinearLayout {
//通过配置文件中,反射实例化设置属性参数。配置文件引用该子view(SettingCenterItemView),调用这里的方法
public SettingCenterItemView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
} //通过代码实例化调用该构造函数
public SettingCenterItemView(Context context) {
super(context);
initView();
} private void initView() {
// TODO Auto-generated method stub } }
继承自LinearLayout,因为LinearLayout属于容器类型的view,他可以填充其他的view。你也可以继承自RelativeLayout都可以
但是,这个时候,好像自定义的SettingCenterItemView什么也不能做。接下来就在initView里面。加载一个布局文件,把这个布局文件转化为一个view组件,再把这个组件加载到容器view中(这里是LinearLayout)。如下:
package com.example.ydlmobileguard.views; import com.example.ydlmobileguard.R; import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout; public class SettingCenterItemView extends LinearLayout { public SettingCenterItemView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
} public SettingCenterItemView(Context context) {
super(context);
initView();
} private void initView() {
//把一个布局文件,转换成一个组件,把这儿组件加载到线性布局中。这里的SettingCenterItemView就有了LinearLayout的功能
View view = View.inflate(getContext(), R.layout.item_settingcenter_view, null);
addView(view);
} }
这时,基本的自定义view其实是完成了。去布局文件引用,就可以引用它了,但是注意:自定义的view,必须view名称要写全名。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" > <TextView
style="@style/tv_title"
android:text="设置中心" /> <com.example.ydlmobileguard.views.SettingCenterItemView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.example.ydlmobileguard.views.SettingCenterItemView> <com.example.ydlmobileguard.views.SettingCenterItemView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.example.ydlmobileguard.views.SettingCenterItemView> </LinearLayout>
重新运行程序,会发现和引入布局显示的效果一样。我们可以使用linearlayout的所有的属性了。自定义view好像是完成了。能像在布局文件中使用LinearLayout一样使用我们自己的view(Settingcenteritemview)了。
还没结束。如果就这么结束了,就成了蒙你了。。。因为还是无法修改每一项的内容,场景还没解决。接下来,还要自定义属性对文字做一个动态修改。
在自定义属性前,先看一下系统的属性是怎么来设置的。
都会发现每一个配置文件中有一行命名空间:xmlns:android="http://schemas.android.com/apk/res/android" 这是系统自带的,它的原理是:通过命名空间的前缀android,找到包的信息(这里是最后一个名称android),通过包的信息,找到工程,找到工程后。就可以找到这个工程的资源信息(values----attrs属性配置文件),从attrs文件里找到属性配置的信息。先在 activity_settingcenter.xml里面加入自己供自定义view使用的命名空间前缀
如下:xmlns:itydl="http://schemas.android.com/apk/res/com.example.ydlmobileguard"
再参考一下系统的attrs文件怎么写的——
<resource>
<declare-styleable name="ViewGroup">
<!-- Defines whether changes in layout (caused by adding and removing items) should
cause a LayoutTransition to run. When this flag is set to true, a default
LayoutTransition object will be set on the ViewGroup container and default
animations will run when these layout changes occur.-->
<attr name="animateLayoutChanges" format="boolean" />
</resource>
在这里面,起着最主要作用的是<attr name="animateLayoutChanges" format="boolean" />一个是属性名称,在布局文件中可以直引用,一个是属性值得类型。
比对之,定义自己的属性文件
新建attrs.xml文件,加入针对自定义view要添加的属性名和属性值
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SettingCenterItemView">
<!-- 添加自己要在自定义view里 加入的属性名和类型 -->
<attr name="title" format="string" />
<attr name="content" format="string" />
</declare-styleable>
</resources>
这个时候,就可以在自定义view配置文件里添加这里定义的属性名称了,是合法的。如下:
<com.example.ydlmobileguard.views.SettingCenterItemView
itydl:title = "自定更新设置"
itydl:content ="自动更新已经关闭"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.example.ydlmobileguard.views.SettingCenterItemView> <com.example.ydlmobileguard.views.SettingCenterItemView
itydl:title = "黑名单拦截设置"
itydl:content ="黑名单拦截设置已经关闭"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.example.ydlmobileguard.views.SettingCenterItemView>
这个时候运行程序,发现还是没有显示上边的文字信息。因为,自定义的属性值,在配置文件写上了,但是在组件里面(自定义SettingCenterItemView类)里面不知道,所以要在里面读取属性的配置信息,在构造方法的AttributeSet attrs里面,并且手动把值加到屏幕上显示(即,通过代码手动加入)。
在SettingCenterItemView类中完成代码如下:
package com.example.ydlmobileguard.views; import com.example.ydlmobileguard.R; import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.TextView; public class SettingCenterItemView extends LinearLayout {
private TextView tv_title;
private TextView tv_content;
private CheckBox cb_checkBox;
/**
* 代码实例化,调用构造函数。引用这个自定义view,就会自动调用这里的构造函数
* @param context
* @param attrs
*/
public SettingCenterItemView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
/**
* namespace :The namespace of the attribute to get the value from.
name :The name of the attribute to get the value from.
*/
//根据参数一:命名空间/参数二:属性文件中的属性名。这样就在自定义组件activity_settingcenter.xml文件中得到值
String title =attrs.getAttributeValue("http://schemas.android.com/apk/res/com.example.ydlmobileguard", "title");
String content = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.example.ydlmobileguard", "content");
//把获取到的值,加载到view上显示
tv_title.setText(title);
tv_content.setText(content);
} public SettingCenterItemView(Context context) {
super(context);
initView();
}
/**
* 初始化LinearLayout子组件
*/
private void initView() {
//给LinearLayout加上子组件
View view = View.inflate(getContext(), R.layout.item_settingcenter_view, null);
//每一项的标题
tv_title = (TextView) view.findViewById(R.id.tv_settingcenter_autoupdate_title);
//每一项内容
tv_content = (TextView) view.findViewById(R.id.tv_settingcenter_autoupdate_content);
//每一项的复选框
cb_checkBox = (CheckBox) view.findViewById(R.id.cb_settingcenter_autoupdate_checked);
addView(view);//Adds a child view.
} }
此时运行程序,屏幕截图如下:
这个时候自定义view算是介绍完了。
最后完成“”特效“,添加背景颜色,添加选择器,点击每一项,chackbox也跟着选中或者取消选中。完整代码在下面给出:
给item——settingcenterview整体加入状态选择器,设置可点击:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="65dip"
android:clickable="true"
android:background="@drawable/bts_selector">
checkbox的点击事件阉割掉,加入一行:
android:clickable="false"
最后自定义view类中的代码如下:
package com.example.ydlmobileguard.views; import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout;
import android.widget.TextView; import com.example.ydlmobileguard.R; public class SettingCenterItemView extends LinearLayout {
private TextView tv_title;
private TextView tv_content;
private CheckBox cb_checkBox;
private String[] contents;
private View item;
/**
* 代码实例化,调用构造函数。引用这个自定义view,就会自动调用这里的构造函数
* @param context
* @param attrs
*/
public SettingCenterItemView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();//初始化组件界面
initEvent();//初始化组件事件
/**
* namespace :The namespace of the attribute to get the value from.
name :The name of the attribute to get the value from.
*/
//根据命名空间/属性文件中的属性值。在自定义组件xml文件中得到值
String title =attrs.getAttributeValue("http://schemas.android.com/apk/res/com.example.ydlmobileguard", "title");
String content = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.example.ydlmobileguard", "content");
//把获取到的值,加载到view上显示
tv_title.setText(title);
//利用正则表达式,截取content内容。自动更新已经关闭-自动更新已经开启。其中,contents[0]=自动更新已经关闭;contents[1]=自动更新已经开启
contents = content.split("-");
} /**
* chu shi hua fu xuan kuang zu jian
*/
private void initEvent() {
//item 我们自定义的相对布局。给整个item_view加入事件(它是自定义的一个view)。让checkbox随着它的点击事件变化
item.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
cb_checkBox.setChecked(!cb_checkBox.isChecked()); }
}); cb_checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked){//clicked选中的颜色为绿色
tv_content.setTextColor(Color.GREEN);
tv_content.setText(contents[1]);
}else{//unclicked//未选中颜色为红色
tv_content.setTextColor(Color.RED);
tv_content.setText(contents[0]);
} }
}); } public SettingCenterItemView(Context context) {
super(context);
initView();
}
/**
* 初始化LinearLayout子组件
*/
private void initView() {
//给LinearLayout加上子组件。这个item指的就是item_settingcenter_view文件里的RelativeLayout
item = View.inflate(getContext(), R.layout.item_settingcenter_view, null);
//每一项的标题
tv_title = (TextView) item.findViewById(R.id.tv_settingcenter_autoupdate_title);
//每一项内容
tv_content = (TextView) item.findViewById(R.id.tv_settingcenter_autoupdate_content);
//每一项的复选框
cb_checkBox = (CheckBox) item.findViewById(R.id.cb_settingcenter_autoupdate_checked);
addView(item);//Adds a child view.
} }
最后再总结一下自定义属性:
自定义属性
1,自定义命名空间
xmlns:ittdl="http://schemas.android.com/apk/res/工程的包名"
2,创建attrs.xml文件
<declare-styleable name="SettingCenterItemView">
<!--
Defines whether a child is limited to draw inside of its bounds or not.
This is useful with animations that scale the size of the children to more
than 100% for instance. In such a case, this property should be set to false
to allow the children to draw outside of their bounds. The default value of
this property is true.
-->
<attr name="title" format="string" />
<attr name="content" format="string" />
</declare-styleable>
3,在自定义组件中使用自定义属性
<com.itydl.mobileguard.view.SettingCenterItemView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
itheima:content="自动更新已经关闭-自动更新已经打开"
itheima:title="自动更新设置" >
</com.itydl.mobileguard.view.SettingCenterItemView>
获取自定义属性数据
public SettingCenterItemView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
initEvent();
String content = attrs.getAttributeValue("http://schemas.android.com/apk/res/工程包名", "自定义属性名");
String title = attrs.getAttributeValue("http://schemas.android.com/apk/res/com.itydl.mobileguard", "title");
tv_title.setText(title);
contents = content.split("-");
}
这仅仅是一个简单的demo,还有更复杂的自定义view也会在以后继续讨论。
Android初级教程初谈自定义view自定义属性的更多相关文章
- Android初级教程:如何自定义一个状态选择器
有这样一种场景:点击一下某个按钮或者图片(view),改变了样式(一般改变背景颜色).这个时候一种解决方案,可能就是状态选择器.接下来就介绍如何实现状态选择器: 步骤: 一.新建这样的文件夹:res/ ...
- Android自定义View自定义属性
1.引言 对于自定义属性,大家肯定都不陌生,遵循以下几步,就可以实现: 自定义一个CustomView(extends View )类 编写values/attrs.xml,在其中编写styleabl ...
- Android 初阶自定义 View 字符头像
自己很少做自定义 View ,只有最开始的时候跟着郭神写了一个小 Demo ,后来随着见识的越来越多,特别是在开源社区看到很多优秀的漂亮的控件,都是羡慕的要死,但是拉下来的代码还是看不明白,而且当时因 ...
- Android初级教程理论知识(第三章测试&数据存储&界面展现)
首先介绍单元测试,我在javaweb部分有详细介绍单元测试框架的一篇文章. 可以先看在javaweb中的单元测试详解篇http://blog.csdn.net/qq_32059827/article/ ...
- Android学习(十七)自定义View控件 TopBar
一.创建自定义TopBar头部菜单条 实现步骤: 1.在values中添加attrs.xml文件,设置自定义属性. 2.添加Topbar类,继承RelativeLayout,实现具体功能. 3.添加到 ...
- Android Studio开发基础之自定义View组件
一般情况下,不直接使用View和ViewGroup类,而是使用使用其子类.例如要显示一张图片可以用View类的子类ImageView,开发自定义View组件可分为两个主要步骤: 一.创建一个继承自an ...
- Android初级教程通过简要分析“土司”源码,来自实现定义土司理论探讨
由于系统自带的土司瞬间即逝,而且非常难看.因此我们就希望自定义自己的土司风格.有些实例就是基于自定义土司完成的,例如金山卫士的火箭发射,基本原理就是个土司.但是在做出自己的土司风格之前,还是要简要分析 ...
- Android圆形图片不求人,自定义View实现(BitmapShader使用)
在很多APP当中,圆形的图片是必不可少的元素,美观大方.本文将带领读者去实现一个圆形图片自定View,力求只用一个Java类来完成这件事情. 一.先上效果图 二.实现思路 在定义View 的onMea ...
- android愤怒小鸟游戏、自定义View、掌上餐厅App、OpenGL自定义气泡、抖音电影滤镜效果等源码
Android精选源码 精练的范围选择器,范围和单位可以自定义 自定义View做的小鸟游戏 android popwindow选择商品规格颜色尺寸效果源码 实现Android带有锯齿背景的优惠样式源码 ...
随机推荐
- ●codeforces 528D Fuzzy Search
题链: http://codeforces.com/problemset/problem/528/D 题解: FFT 先解释一下题意: 给出两个字符串(只含'A','T','C','G'四种字符),一 ...
- 【USACO Feb 2014】Cow Decathlon
题目描述 约翰有 N 头奶牛,组成了一直队伍参加全能比赛.比赛一共有 N 项,每头奶牛必须参加一项比 赛,每项比赛也必须有一头奶牛参加.任何一头奶牛可以胜任任何一项比赛,但得分不一样.如果第 i 头奶 ...
- 【Miller-Rabin随机判素数算法】
实用性介绍: #include<bits/stdc++.h> #define go(i,a,b) for(int i=a;i<=b;i++) #define T 5 #define ...
- Python中模块json与pickle的功能介绍
json & pickle & shelve 1. json的序列化与反序列化 json的使用需要导入该模块,一般使用import json即可. json的序列化 方法1:json. ...
- HTTP Status Codes 查询表
Web项目中经常会出现各种状态码,今天看到一个博客,挺不错,记录下来.
- openwrt 下添加sim760ce usb驱动
SIM7500_SIM7600 系列模块的 USB VID 是 0x1E0E PID 是 0x9001. 作为 Slave USB 设备,配置如下表 USB 接口波特率自适应 9600.115200 ...
- 前端工程师:电信专业转前端是如何拿到阿里、腾讯offer的?
1.个人情况 ● 211本科 985硕士 电信专业 女生 ● 16年3月开始学习前端 ● 16年7月开始实习,共五家实习经历(不是特别厉害的厂) ● 秋招拿到两个offer(阿里.腾讯).没错只有这两 ...
- 代码之间-论文修改助手v1.0版本发布
论文查重,是每个毕业生都要面临的一个令人头疼的问题,如果写论文不认真,很可能导致查重红一大片. 之前有帮助一些朋友修改论文降低重复率,做了一些工作后发现,国内的查重机构,如知网.维普等,大多数是基于关 ...
- Java 求n天前的时间或者n月前的时间
时间格式化 public static String DEFAULT_FORMATDATE = "yyyy-MM-dd"; 1.n天前的日期 /** * luyanlong * 默 ...
- 关于云Linux部署tomcat服务器(Maven的多模块war包)
博主的运行环境: 电脑系统: Linux mint 18 JDK版本: java version "1.8.0_171" Maven版本: Apache Maven 3.5.3 ...