Android学习笔记:自定义控件篇

      学校里面开了门安卓课,为了作业,就开始学习安卓的各种知识。UI是最能直观看到的东西,所以我就从自定义控件开始。

      首先,我说一下,为什么要自定义控件呢?1.原生的控件不足以满足我们的要求,或者有些功能与我们的要求不太相同等,比如说,要用一个带删除按钮的编辑框,原生的里面就没有;2.有很多控件是可以复用的,像导航栏,标题栏这种可能需要多次使用的东东,如果每次都是靠原生控件堆叠起来,然后拷贝多份的话,那么不仅费时费力,而且可维护性太差,如果要改东西的话,很容易出差错。

      那接下来,就该步入正题了,那就是如何来自定义控件。基本上,我们可以把它拆解为3个部分:1.设计需要的属性;2.实现自定义的控件;3.引用自定义的控件


一、设计需要的属性

        在res/value目录下面新建一个xml文件,命名为attrs.xml。里面需要用到许多属性,来限制不同参数的类型,具体的含义可以在下面的链接中查看:
http://googlers.iteye.com/blog/1122585
        下面是我写的一个attrs.xml中的内容,定义了一个Detailbar的相关属性,之后可以像设置系统原生控件属性那样设置自定义控件的属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <declare-styleable name="Detailbar">
        <attr name="info" format="string"></attr>
        <attr name="infoTextSize" format="dimension"></attr>
        <attr name="infoTextColor" format="color"></attr>
        <attr name="infoBackground" format="reference|color"></attr>
        
        <attr name="leftText" format="string"></attr>
        <attr name="leftTextSize" format="dimension"></attr>
        <attr name="leftTextColor" format="color"></attr>
        <attr name="leftBackground" format="reference|color"></attr>
        
        <attr name="rightText" format="string"></attr>
        <attr name="rightTextSize" format="dimension"></attr>
        <attr name="rightTextColor" format="color"></attr>
        <attr name="rightBackground" format="reference|color"></attr>
    </declare-styleable>
</resources>
二、 实现自定义的控件
继承某个控件的类,然后再这个类里面将控件的布局,控件的行为等加以定义和调整,原则上是参照Android的系统控件的实现方法来完成。
上代码:
package com.wecall.contacts.view;

import com.wecall.contacts.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * 自定义个人详细信息tab
 * 
 * @author xiaoxin
 *
 */
public class DetailBar extends RelativeLayout {

	//内部的控件
	private Button leftBtn,rightBtn;
	private TextView tvInfo;
	
	//内部控件的信息
	private String leftText;
	private int leftTextColor;
	private float leftTextSize;
	private Drawable leftBackground;
	
	private String rightText;
	private int rightTextColor;
	private float rightTextSize;
	private Drawable rightBackground;
	
	private String infoText;
	private int infoTextColor;
	private float infoTextSize;
	private Drawable infoBackground;
	
	private LayoutParams leftParams,rightParams,infoParams;
	
	//定义接口
	public interface DetailBarClickListener{
		void leftClick();
		void rightClick();
		void infoClick();
	}
	
	private DetailBarClickListener listener;
	
	//开放给外部的方法
	public void setOnDetailBarClickListener(DetailBarClickListener listener){
		this.listener = listener;
	}
	
	//实现两个参数的构造方法,其中第二个参数为传入的参数集合
	public DetailBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		//初始化惨呼
		initAttrs(context,attrs);
		//初始化内部控件
		initView(context);
		
	}
	
	public String getInfo(){
		return tvInfo.getText().toString();
	}

	private void initAttrs(Context context, AttributeSet attrs) {
		
		TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.Detailbar);
		
		leftText = ta.getString(R.styleable.Detailbar_leftText);
		leftTextColor = ta.getColor(R.styleable.Detailbar_leftTextColor, 0);
		leftTextSize = ta.getDimension(R.styleable.Detailbar_leftTextSize, 0);
		leftBackground = ta.getDrawable(R.styleable.Detailbar_leftBackground);
		
		rightText = ta.getString(R.styleable.Detailbar_rightText);
		rightTextColor = ta.getColor(R.styleable.Detailbar_rightTextColor, 0);
		rightTextSize = ta.getDimension(R.styleable.Detailbar_rightTextSize, 0);
		rightBackground = ta.getDrawable(R.styleable.Detailbar_rightBackground);
		
		infoText = ta.getString(R.styleable.Detailbar_infoText);
		infoTextColor = ta.getColor(R.styleable.Detailbar_infoTextColor, 0);
		infoTextSize = ta.getDimension(R.styleable.Detailbar_infoTextSize, 0);
		infoBackground = ta.getDrawable(R.styleable.Detailbar_infoBackground);
		
		ta.recycle();
	}

	private void initView(Context context) {
		leftBtn = new Button(context);
		rightBtn = new Button(context);
		tvInfo = new TextView(context);
		
		leftBtn.setText(leftText);
		leftBtn.setTextColor(leftTextColor);
		leftBtn.setTextSize(leftTextSize);
		leftBtn.setBackground(leftBackground);
		
		rightBtn.setText(rightText);
		rightBtn.setTextColor(rightTextColor);
		rightBtn.setTextSize(rightTextSize);
		rightBtn.setBackground(rightBackground);
		
		tvInfo.setText(infoText);
		tvInfo.setTextColor(infoTextColor);
		tvInfo.setTextSize(infoTextSize);
		tvInfo.setBackground(infoBackground);
		tvInfo.setGravity(Gravity.CENTER);
		
		setBackgroundColor(0xfff59563);
		
		leftParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
		leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);
		leftParams.addRule(RelativeLayout.CENTER_VERTICAL,TRUE);
		addView(leftBtn,leftParams);
		
		rightParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
		rightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);
		rightParams.addRule(RelativeLayout.CENTER_VERTICAL,TRUE);
		addView(rightBtn,rightParams);
		
		infoParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);
		infoParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE);
		addView(tvInfo,infoParams);
		
		leftBtn.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				listener.leftClick();
			}
		});
		
		rightBtn.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				listener.rightClick();
			}
		});
		
		tvInfo.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				listener.infoClick();
			
		});
	}
}
三、使用自定义控件
在布局文件中使用自定义控件的时候,要申请一个xml的命名空间,就是布局文件第一行那个xmlns,ns是namespace的缩写。参照那个写法:xmlns:android="http://schemas.android.com/apk/res/android", 我们申请命名空间xmlns:custom="http://schemas.android.com/apk/res-auto"
格式是:xmlns:命名空间="http://schemas.android.com/apk/res/应用包名",注意,是应用的包名,不是自定义控件类的包名,系统允许将“res/应用包名”写出"res-auto",它会自动帮你找到参数定义
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center_vertical">
        
    <ImageButton android:id="@+id/back_to_homepage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_menu_back"
        android:background="@null"
        android:layout_gravity="center_vertical"/>
        
    <TextView android:id="@+id/tv_contact_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:text="齐天大圣"
        android:textSize="30sp"
        android:layout_margin="20dp"/>
    </LinearLayout>
    
	<com.wecall.contacts.view.DetailBar 
	    android:id="@+id/phone_num"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        custom:infoText="1234567890"
        custom:infoTextColor="#ffffff"
        custom:infoTextSize="20sp"
        custom:leftBackground="@drawable/sym_action_call"
        custom:rightBackground="@drawable/sym_action_email"
        >
        
    </com.wecall.contacts.view.DetailBar>
    

</LinearLayout>
</ScrollView>
在Activity中使用的时候,就是跟使用其他控件是一样的
package com.wecall.contacts;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;

import com.wecall.contacts.view.DetailBar;
import com.wecall.contacts.view.DetailBar.DetailBarClickListener;

public class ContactInfo extends Activity {

	private TextView nameTV;
	private ImageButton backIB;
	private DetailBar phoneNumBar;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.contact_info);
		initView();
	}

	private void initView() {
		nameTV = (TextView)findViewById(R.id.tv_contact_name);
		backIB = (ImageButton)findViewById(R.id.back_to_homepage);
		phoneNumBar = (DetailBar)findViewById(R.id.phone_num);
		Bundle bundle = getIntent().getExtras();

		nameTV.setText(bundle.getString("cname"));
		
		backIB.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				finish();
			}
		});
		
		phoneNumBar.setOnDetailBarClickListener(new DetailBarClickListener() {
			
			@Override
			public void leftClick() {
				String phoneNumber = phoneNumBar.getInfo().toString();
				Intent intent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:"+phoneNumber));
				ContactInfo.this.startActivity(intent);
			}
			
			@Override
			public void rightClick() {
				String phoneNumber = phoneNumBar.getInfo().toString();
				Intent intent = new Intent(Intent.ACTION_SENDTO,Uri.parse("smsto:"+phoneNumber));
				ContactInfo.this.startActivity(intent);
			}
			
			@Override
			public void infoClick() {
				Log.v("TAG","info");
			}
		});
	}
}
这个是我写的代码中选取的一部分,删了点东西,而且也不是MainActivity,所以直接拷贝,可能会有点错误,不过原理上是没有问题的,大家看一下,了解一下原理就OK。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值