我们在扣扣 微信等界面 都可以看到如下图 红色方框里面的 中间是标题 两边是按钮
如果很多页面都需要类似的功能 ,我们则可以自己制作一个这样的控件,然后就可以引用,省去好多麻烦。
下面则是如何制作这样的控件
一 、首先在values文件下 新建一个attrs.xml文件,其代码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Topbar">
<attr name="leftTextColor" format="color" />
<attr name="leftBackground" format="reference|color" />
<attr name="leftText" format="string" />
<attr name="title" format="string" />
<attr name="titleTextSize" format="dimension" />
<attr name="titleTextColor" format="color" />
<attr name="rightTextColor" format="color" />
<attr name="rightBackground" format="reference|color" />
<attr name="rightText" format="string" />
</declare-styleable>
</resources>
其中:<declare-styleable name="Topbar"> declare-styleable 是指自定义意思,我们自己定义新的控件时候则需要用declare-styleable 来声明(除了自带的),name ="Topbar" 指的是 控件的名字是Topbar。
<attr name="leftTextColor" format="color" />
<attr name="leftBackground" format="reference|color" />
<attr name="leftText" format="string" />
里面的 name="leftTextColor" 表示的是属性的名字是leftTextColor ,就像android:textcolor 一样;format="color" 是指格式是color类型的
这里的自定义属性的format,可以有很多种:
- reference
- string
- color
- dimension
- boolean
- integer
- float
- fraction
- enum
- flag
二、创建Topbar.java类 代码如下:
package com.example.myview;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
<strong>public class Topbar extends RelativeLayout</strong> {
private Button leftButton, rightButton;
private TextView tvTitle;
private int leftTextColor;
private Drawable leftBackground;
private String leftText;
private int rightTextColor;
private Drawable rightBackground;
private String rightText;
private float titleTextSize;
private int titleTextColor;
private String title;
private LayoutParams titlepParams, leftpParams, rightpParams;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@SuppressLint("NewApi")
<strong>public Topbar(final Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs,
R.styleable.Topbar);</strong>
leftTextColor = ta.getColor(R.styleable.Topbar_leftTextColor, 0);
leftBackground = ta.getDrawable(R.styleable.Topbar_leftBackground);
leftText = ta.getString(R.styleable.Topbar_leftText);
rightTextColor = ta.getColor(R.styleable.Topbar_rightTextColor, 0);
rightBackground = ta.getDrawable(R.styleable.Topbar_rightBackground);
rightText = ta.getString(R.styleable.Topbar_rightText);
titleTextSize = ta.getDimension(R.styleable.Topbar_titleTextSize, 0);
titleTextColor = ta.getColor(R.styleable.Topbar_titleTextColor, 0);
title = ta.getString(R.styleable.Topbar_title);
<strong>ta.recycle();</strong>
leftButton = new Button(context);
rightButton = new Button(context);
tvTitle = new TextView(context);
leftButton.setTextColor(leftTextColor);
leftButton.setBackground(leftBackground);
leftButton.setText(leftText);
rightButton.setTextColor(rightTextColor);
rightButton.setBackground(rightBackground);
rightButton.setText(rightText);
tvTitle.setText(title);
tvTitle.setTextColor(titleTextColor);
tvTitle.setTextSize(titleTextSize);
tvTitle.setGravity(Gravity.CENTER);
setBackgroundColor(0xfff59563);
leftpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
leftpParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
addView(leftButton, leftpParams);
rightpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
rightpParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
addView(rightButton, rightpParams);
titlepParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
titlepParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
addView(tvTitle, titlepParams);
}
}
关于
TypedArray 其api如下
方法摘要 | |
---|---|
boolean | getBoolean(int index, boolean defValue) Retrieve the boolean value for the attribute at index. |
int | getColor(int index, int defValue) Retrieve the color value for the attribute at index. |
ColorStateList | getColorStateList(int index) Retrieve the ColorStateList for the attribute at index. |
float | getDimension(int index, float defValue) Retrieve a dimensional unit attribute at index. |
int | getDimensionPixelOffset(int index, int defValue) Retrieve a dimensional unit attribute at index for use as an offset in raw pixels. |
int | getDimensionPixelSize(int index, int defValue) Retrieve a dimensional unit attribute at index for use as a size in raw pixels. |
Drawable | getDrawable(int index) Retrieve the Drawable for the attribute at index. |
float | getFloat(int index, float defValue) Retrieve the float value for the attribute at index. |
float | getFraction(int index, int base, int pbase, float defValue) Retrieve a fractional unit attribute at index. |
int | getIndex(int at) Return an index in the array that has data. |
int | getIndexCount() Return the number of indices in the array that actually have data. |
int | getInt(int index, int defValue) Retrieve the integer value for the attribute at index. |
int | getInteger(int index, int defValue) Retrieve the integer value for the attribute at index. |
int | getLayoutDimension(int index, int defValue) Special version of getDimensionPixelSize(int, int) for retrieving ViewGroup's layout_width and layout_height attributes. |
int | getLayoutDimension(int index, String name) Special version of getDimensionPixelSize(int, int) for retrieving ViewGroup's layout_width and layout_height attributes. |
String | getNonResourceString(int index) Retrieve the string value for the attribute at index, but only if that string comes from an immediate value in an XML file. |
String | getPositionDescription() Returns a message about the parser state suitable for printing error messages. |
int | getResourceId(int index, int defValue) Retrieve the resource identifier for the attribute at index. |
Resources | getResources() Return the Resources object this array was loaded from. |
String | getString(int index) Retrieve the string value for the attribute at index. |
CharSequence | getText(int index) Retrieve the styled string value for the attribute at index. |
CharSequence[] | getTextArray(int index) Retrieve the CharSequence[] for the attribute at index. |
boolean | getValue(int index, TypedValue outValue) Retrieve the raw TypedValue for the attribute at index. |
boolean | hasValue(int index) Determines whether there is an attribute at index. |
int | length() Return the number of values in this array. |
TypedValue | peekValue(int index) Retrieve the raw TypedValue for the attribute at index and return a temporary object holding its data. |
void | recycle() Give back a previously retrieved StyledAttributes, for later re-use. |
String | toString() Returns a string containing a concise, human-readable description of this object. |
下面说说AttributeSet与TypedArray在自定义控件中的作用:
AttributeSet的作用就是在控件进行初始化的时候,解析布局文件中该控件的属性(key eg:background)与该值(value eg:@drawable/icon)的信息封装在AttributeSet中,传递给该控件(View)的构造函数。对于非Android自带的属性,在View类中处理时是无法识别的,因此需要我们自己解析。所以这就要用到另外一个类TypedArray。在AttributeSet中我们有属性名称,有属性值,但是控件如何知道哪个属性代表什么意思呢?这个工作就由TypedArray来做了。TypedArray对象封装了/values/attrs.xml中的styleable里定义的每个属性的类型信息,通过TypedArray我们就可以知道AttributeSet中封装的值到底是干什么的了,从而可以对这些数据进行应用。
AttributeSet就相当于一盒糖,TypedArray就相当于这盒糖上的标签说明,告诉用户每个糖的口味等。这盒糖有什么口味是由用户自己的styleable文件里面的内容来决定的。
TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.Topbar); 第二个参数 R.styleable.Topbar 就是attrs.xml里面的控件。
leftTextColor = ta.getColor(R.styleable.Topbar_leftTextColor, 0); 为左边按钮的文字设置颜色,当我们输入R.stylable. 的时候 就会有代码提示Topbar_leftTextColor,指的是attrs.xml文件里面 Topbar控件的leftTextColor属性 。第二个参数是defValue,代码中的意思是如果第一个参数没有找到对应的资源,则返回defValue设置的值。
leftBackground = ta.getDrawable(R.styleable.Topbar_leftBackground); 为左边按钮设置背景图片
leftText = ta.getString(R.styleable.Topbar_leftText); 为左边按钮设置名字
ta.recycle(); 调用结束后务必调用recycle()方法,否则这次的设定会对下次的使用造成影响 。
leftButton = new Button(context);
rightButton = new Button(context);
tvTitle = new TextView(context);
上面进行实例化
leftButton.setTextColor(leftTextColor); 为左边按钮添加字体颜色
leftButton.setBackground(leftBackground); 为左边按钮添加背景图片
leftButton.setText(leftText);为左边按钮添加名字
setBackgroundColor(0xfff59563); 为整体添加背景颜色
leftpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
为左边按钮设置属性 类似于 android:layout_width="wrap_content" android:layout_height="wrap_content"
leftpParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
为左边按钮增加规则 类似于 android:layout_alignParentLeft="true"
addView(leftButton, leftpParams);
把左边按钮添加到视图中。
三、在activity_main.xml 文件中引入自作的控件
其代码如下
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<strong> xmlns:custom="http://schemas.android.com/apk/res/com.example.myview"</strong>
xmlns:tools="http://schemas.android.com/tools"
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="com.example.myview.MainActivity" >
<strong><com.example.myview.Topbar</strong>
android:id="@+id/topbar"
android:layout_width="wrap_content"
android:layout_height="40dp"
<strong> custom:leftBackground="@drawable/ic_launcher"
custom:leftText="Back"
custom:leftTextColor="#ffffff"
custom:rightBackground="@drawable/ic_launcher"
custom:rightText="More"
custom:rightTextColor="#ffffff"
custom:title="自定义标题"
custom:titleTextColor="#000000"
custom:titleTextSize="12sp" /></strong>
</RelativeLayout>
我们需要在布局文件里面添加一些代码
1.如果用eclipse 编辑代码的话添加 xmlns:custom="http://schemas.android.com/apk/res/com.example.myview" custom 是命名空间 可以自己命名 ,com.example.myview 则是文件的具体包名。
2.如果用as编辑代码则 需要添加代码是 xmlns:custom="http://schemas.android.com/apk/res-auto
custom:leftBackground="@drawable/ic_launcher"
左边按钮的背景图片 (我采用的是系统的自带的,大家可以网上找关于按钮的背景图片)
custom:leftText="Back"
左边按钮的 名字为 "Back"。
custom:leftTextColor="#ffffff"
左边按钮的名字的颜色 。
custom:title="自定义标题"
中间标题的名字为"自定义标题"
custom:titleTextColor="#000000"
中间标题的颜色
custom:titleTextSize="12sp"
写完代码 在视图中可能看不到效果图 但是没关系 ,运行下 可以看到效果如下图
四、为按钮添加点击事件
如果只有按钮没有点击功能,那么岂不是白费力气
在Topbar.xml里面添加如下代码
private TopbarClickListener listener;
public interface TopbarClickListener {
<strong>public void backClick();
public void morekClick();</strong>
};
public void setOnTopbarClickListener(TopbarClickListener listener) {
this.listener = listener;
}
leftButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
<strong>listener.backClick();</strong>
}
});
rightButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
<strong>listener.morekClick()</strong>;
}
});
在MainActivity.java 里面代码如下
package com.example.myview;
import com.example.myview.Topbar.TopbarClickListener;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Topbar topbar = (Topbar) findViewById(R.id.topbar);
topbar.setOnTopbarClickListener(new TopbarClickListener() {
@Override
public void morekClick() {
Toast.makeText(MainActivity.this, "hello", Toast.LENGTH_SHORT).show();
}
@Override
public void backClick() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "JAVA", Toast.LENGTH_SHORT).show();
}
});
//<span style="font-family: monospace; white-space: pre; background-color: rgb(240, 240, 240);">topbar.leftbuttonIsVisiable(false);//隐藏左边按钮</span>
}
}
五、完善
有时候我们需要隐藏一个按钮 不让其显示,以隐藏左边按钮为例
在Topbar.xml添加一个方法
public void leftbuttonIsVisiable(boolean bool) {
if (bool) {
leftButton.setVisibility(View.VISIBLE);
} else {
leftButton.setVisibility(View.GONE);
}
}
通过判断传进参数是真假 来隐藏按钮
在MainActivity.java 需要加一句代码
topbar.leftbuttonIsVisiable(false);//隐藏左边按钮
Topbar.xml里面完整代码如下
package com.example.myview;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class Topbar extends RelativeLayout {
private Button leftButton, rightButton;
private TextView tvTitle;
private int leftTextColor;
private Drawable leftBackground;
private String leftText;
private int rightTextColor;
private Drawable rightBackground;
private String rightText;
private float titleTextSize;
private int titleTextColor;
private String title;
private LayoutParams titlepParams, leftpParams, rightpParams;
private TopbarClickListener listener;
public interface TopbarClickListener {
public void backClick();
public void morekClick();
};
public void setOnTopbarClickListener(TopbarClickListener listener) {
this.listener = listener;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@SuppressLint("NewApi")
public Topbar(final Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs,
R.styleable.Topbar);
leftTextColor = ta.getColor(R.styleable.Topbar_leftTextColor, 0);
leftBackground = ta.getDrawable(R.styleable.Topbar_leftBackground);
leftText = ta.getString(R.styleable.Topbar_leftText);
rightTextColor = ta.getColor(R.styleable.Topbar_rightTextColor, 0);
rightBackground = ta.getDrawable(R.styleable.Topbar_rightBackground);
rightText = ta.getString(R.styleable.Topbar_rightText);
titleTextSize = ta.getDimension(R.styleable.Topbar_titleTextSize, 0);
titleTextColor = ta.getColor(R.styleable.Topbar_titleTextColor, 0);
title = ta.getString(R.styleable.Topbar_title);
ta.recycle();
leftButton = new Button(context);
rightButton = new Button(context);
tvTitle = new TextView(context);
leftButton.setTextColor(leftTextColor);
leftButton.setBackground(leftBackground);
leftButton.setText(leftText);
rightButton.setTextColor(rightTextColor);
rightButton.setBackground(rightBackground);
rightButton.setText(rightText);
tvTitle.setText(title);
tvTitle.setTextColor(titleTextColor);
tvTitle.setTextSize(titleTextSize);
tvTitle.setGravity(Gravity.CENTER);
setBackgroundColor(0xfff59563);
leftpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
leftpParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
addView(leftButton, leftpParams);
rightpParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
rightpParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
addView(rightButton, rightpParams);
titlepParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
titlepParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
addView(tvTitle, titlepParams);
leftButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
listener.backClick();
}
});
rightButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
listener.morekClick();
}
});
}
public void leftbuttonIsVisiable(boolean bool) {
if (bool) {
leftButton.setVisibility(View.VISIBLE);
} else {
leftButton.setVisibility(View.GONE);
}
}
}