Android UI开发详解之模板控件的复用

Android的UI设计一直是Android程序员比较苦恼的一件事,本文主要讲解如何将一些模板类控件进行复用,从而简化UI的开发。

如图:



我们很多程序的界面中,顶部的TopBar是不变的,所以,我们可以做一个公用的控件模板,每次使用时,只要设置相应的参数,就能生成这样一个TopBar。

模板控件实现方法:

package com.xys.multiplexedmodule;

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

public class MultipleTopBar extends RelativeLayout{

	private Button btn_left;
	private Button btn_right;
	private TextView tv_title;

	private TopBarClickListener topBarClickListener;
	private String str_title;

	private RelativeLayout.LayoutParams leftButtonLayoutParams;
	private RelativeLayout.LayoutParams rightButtonLayoutParams;
	private RelativeLayout.LayoutParams tvTitleLayoutParams;

	private static int leftBtnId=1;
	private static int titleTvId=2;
	private static int rightBtnId=3;

	private Drawable leftBtnBackground;
	private Drawable rightBtnBackground;

	private String str_LeftBtn;
	private String str_RightBtn;
	private int leftBtnColor;
	private int rightBtnColor;
	private int titleTvColor;

	private float titleTextSize;

	public MultipleTopBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		//从参数列表中获取参数
		//TypedArray实例是个属性的容器,context.obtainStyledAttributes()方法返回得到。AttributeSet是节点的属性集合
		//第二个参数为 为获取到值时的默认值
		TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.TopBar);
		this.str_title=ta.getString(R.styleable.TopBar_title);
		this.leftBtnBackground=ta.getDrawable(R.styleable.TopBar_leftBackground);
		this.rightBtnBackground=ta.getDrawable(R.styleable.TopBar_rightBackground);
		this.str_LeftBtn=ta.getString(R.styleable.TopBar_leftText);
		this.str_RightBtn=ta.getString(R.styleable.TopBar_rightText);
		this.leftBtnColor=ta.getColor(R.styleable.TopBar_leftTextColor, 0);
		this.rightBtnColor=ta.getColor(R.styleable.TopBar_rightTextColor, 0);
		this.titleTextSize=ta.getDimension(R.styleable.TopBar_titleTextSize, 14);
		this.titleTvColor=ta.getColor(R.styleable.TopBar_titleTextColor, 0);

		ta.recycle();

		btn_left=new Button(context);
		btn_right=new Button(context);
		tv_title=new TextView(context);

		btn_left.setId(leftBtnId);
		btn_right.setId(rightBtnId);
		tv_title.setId(titleTvId);

		//为组件配置布局参数
		leftButtonLayoutParams=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
		rightButtonLayoutParams=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
		tvTitleLayoutParams=new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);

		leftButtonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,RelativeLayout.TRUE);
		leftButtonLayoutParams.setMargins(12, 0, 0, 0);//左上右下
		leftButtonLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);

		rightButtonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,RelativeLayout.TRUE);
		rightButtonLayoutParams.setMargins(0, 0, 12, 0);//左上右下
		rightButtonLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);

		tvTitleLayoutParams.setMargins(12, 0, 12, 0);//左上右下
		tvTitleLayoutParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
		tvTitleLayoutParams.addRule(RelativeLayout.LEFT_OF, rightBtnId);
		tvTitleLayoutParams.addRule(RelativeLayout.RIGHT_OF, leftBtnId);
		//tvTitleLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
		tv_title.setGravity(Gravity.CENTER);
		tv_title.setBackgroundColor(leftBtnColor);

        addView(btn_left, leftButtonLayoutParams);
        addView(btn_right,rightButtonLayoutParams);
        addView(tv_title,tvTitleLayoutParams);

        //btn_left.setBackgroundDrawable(leftBtnBackground);
        btn_left.setText(str_LeftBtn);
        btn_left.setTextColor(leftBtnColor);
        //btn_right.setBackgroundDrawable(rightBtnBackground);
        btn_right.setText(str_RightBtn);
        btn_right.setTextColor(rightBtnColor);

        tv_title.setTextSize(22.0f);
        tv_title.setTextColor(Color.BLUE);
        tv_title.setEllipsize(TruncateAt.MIDDLE);
        tv_title.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
        tv_title.setSingleLine(true);
        tv_title.setText(str_title);
        tv_title.setTextSize(titleTextSize);
        tv_title.setTextColor(titleTvColor);

        btn_left.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					// TODO Auto-generated method stub
					if(topBarClickListener!=null){
                        topBarClickListener.leftBtnClick();
                }
				}
        });

        btn_right.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                        if(topBarClickListener!=null){
                                topBarClickListener.rightBtnClick();
                        }
                }
        });

	}

	/*
	 * 单击监听事件
	 */
	public void setTopBarClickListener(TopBarClickListener topBarClickListener){
		this.topBarClickListener=topBarClickListener;
	}
}

监听接口:

package com.xys.multiplexedmodule;

public interface TopBarClickListener {

	void leftBtnClick();
	void rightBtnClick();
}

对我们自定义的模板控件,我们需要设定他的一些参数,在Values下新建attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--declare-styleable:自定义属性的值  -->
    <declare-styleable name="TopBar">
        <attr name="title" format="string" />
        <attr name="titleTextSize" format="dimension" />
        <attr name="titleTextColor" format="color" />
        <attr name="leftTextColor" format="color" />
        <attr name="leftBackground" format="string" />
        <attr name="leftText" format="string" />
        <attr name="rightTextColor" format="color" />
        <attr name="rightBackground" format="string" />
        <attr name="rightText" format="string" />
    </declare-styleable>

</resources>

现在我们就已经做好了一个模板,我们要如何使用他呢,很简单:

测试类:

package com.xys.multiplexedmodule;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Toast;

public class TestActivity extends Activity {

	private MultipleTopBar topBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        topBar=(MultipleTopBar)findViewById(R.id.topBar);
        topBar.setTopBarClickListener(new TopBarClickListener() {

			@Override
			public void rightBtnClick() {
				// TODO Auto-generated method stub
				Toast.makeText(TestActivity.this, "你点击的是右边的按钮", Toast.LENGTH_LONG).show();
			}

			@Override
			public void leftBtnClick() {
				// TODO Auto-generated method stub
				Toast.makeText(TestActivity.this, "你点击的是左边的按钮", Toast.LENGTH_LONG).show();
			}
		});
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

引用模板的布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res/com.xys.multiplexedmodule"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".TestActivity" >
	<!--一定要加入引用 xmlns:custom="http://schemas.android.com/apk/res/com.xys.multiplexedmodule"  -->
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:orientation="vertical" >

        <com.xys.multiplexedmodule.MultipleTopBar
            android:id="@+id/topBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            custom:leftBackground="@drawable/ic_launcher"
            custom:leftText="左侧"
            custom:leftTextColor="#ff0000"
            custom:rightBackground="@drawable/ic_launcher"
            custom:rightText="右侧"
            custom:rightTextColor="#ff0000"
            custom:title="自定义标题"
            custom:titleTextColor="#123412"
            custom:titleTextSize="14.0sp" >
        </com.xys.multiplexedmodule.MultipleTopBar>
    </LinearLayout>

</RelativeLayout>

这样我们就可以使用我们新建的模板控件了,效果如下:

时间: 2024-09-15 02:01:30

Android UI开发详解之模板控件的复用的相关文章

Android UI开发详解之ActionBar

在Android3.0之后,Google对UI导航设计上进行了一系列的改革,其中有一个非常好用的新功能就是引入的ActionBar,他用于取代3.0之前的标题栏,并提供更为丰富的导航效果. 一.添加ActionBar 1.不需要导入ActionBar,因为在android3.0或者以上版本中,ActionBar已经默认的包含在Activity中 2.在Android3.0的默认主题"holographic"中,已经创造了ActionBar 3.当android:minSdkVersio

Android UI开发详解之Fragment

Fragment是Android自从3.0之后新加入的一个组件,我相信很多人都已经听说过这个组件了,但这个组件到底是个什么,如何去使用他呢,且听我讲来. 以下部分资料来自官网(官网才是王道,其他都是浮云) 一.Fragment要点 Fragment作为Activity界面的一部分组成出现 可以在一个Activity中同时出现多个Fragment,并且,一个Fragment亦可在多个Activity中使用. 在Activity运行过程中,可以添加.移除或者替换Fragment(add().remo

Android UI开发详解之Layout_gravity和gravity的区别

对于这两个属性来说: layout_gravity   表示组件自身在父组件中的位置 gravity                表示组件的子组件在组件中的位置 1.在使用时,最外层的LinearLayou的属性:androidrientation="?"是不能少的. 但我们在设置其属性的时候,有时候并不能达到我们所需要的效果,所以在此总结下他的使用注意事项. 2.当作为父layout的LinearLayout的属性为androidrientation="vertical&

《Android游戏开发详解》一2.9 类

2.9 类 Android游戏开发详解图2-19所示的一个对象框架,如何将其转换为Java代码呢?使用类(class).我们已经创建了很多类,但是,还没有介绍什么是类. 类提供了一个模板,以供创建Java对象.常用的类比把类描述为一个蓝图.如下是一个Phone类的样子. 程序清单2.8 Phone类的一个示例 01 public class Phone { 02 03 // These variables describe the Phone object's state 04 boolean

《Android游戏开发详解》——第2章,第2.9节类

2.9 类Android游戏开发详解图2-19所示的一个对象框架,如何将其转换为Java代码呢?使用类(class).我们已经创建了很多类,但是,还没有介绍什么是类. 类提供了一个模板,以供创建Java对象.常用的类比把类描述为一个蓝图.如下是一个Phone类的样子. 程序清单2.8 Phone类的一个示例 01 public class Phone { 02 03 // These variables describe the Phone object's state 04 boolean p

《Android游戏开发详解》——第3章,第3.6节图形

3.6 图形Android游戏开发详解基于文本的程序很容易构建,但是基于文本的游戏已经过时了.在本节中,我们将介绍如何使用Java类库中的类(尤其是javax.swing包中的类),来创建一个图形用户界面(Graphical User Interface ,GUI).你会发现,尽管添加一个简单的用户界面很直接,但GUI是一个很大的主题.我将只是提供一个快速的介绍,完全只是创建一个窗口和显示一个基于Java的游戏所需要的基础知识.如果你想要学习Swing的更多知识,并且要创建专业的应用程序,请访问

android网络应用开发详解

Android网络应用开发,主要有两种方式,一种是socket(是对tcp/udp协议的封装),另外一种就是使用Http协议,Android中主要提供了两种方式,HttpURLConnection和Apache HttpClient.下面对Android网络应用开发进行具体的阐述. 一.基于socket的网络通信 socket是为了网络服务提供的一种机制.通信的两端都是socket. 网络通信其实就是socket间的通信. 数据在两个socket间进行io传输. 1.基于udp的socket编程

android应用开发详解里的一个例子

问题描述 android应用开发详解里的一个例子 我导入的书上例子可以运行,照着书打进去的代码就不能运行,同样从例子里面复制过来的代码也不能运行,MainActivity可以显示,但是点击register后跳转的ResultActivity就不能显示,模拟器弹出has stopped字样,求解答 以下是代码 package com.amaker.test; import android.app.Activity; import android.content.Intent; import and

《Android游戏开发详解》一2.20 对象的更多实践——模拟一个色子

2.20 对象的更多实践--模拟一个色子 Android游戏开发详解 在我们的下一个项目中,将模拟一个六面色子的滚动.色子会出现在许多现代的桌上游戏中,因为它们增添了不可预期的因素,如图2-26所示.在本节中,我们将展示在Java程序中如何模拟这种随机性. 我们首先创建一个名为"DiceProject"的新的Java项目.其中,创建一个名为DiceMaker的新的类,并且像通常一样给它一个main方法. 要产生一个随机数,我们必须使用Java库中名为Random的一个内建类.我们使用熟