自定义view分为三种:
1、直接继承View
2、继承现有控件
3、组合现有控件,组成新的控件。
组合控件就属于第三种,算是最简单的一种了吧
虽然知道简单,但是还是决定写一篇博客,熟悉一下流程,温故而知新吧
一、定义需要组合控件的视图,当然也可以在代码中定义
例如:定义一个button
Button button=new Button();
简单的还好,但是如果是复杂的布局就需要写大量的代码,得不偿失,还是写到布局文件里面比较好,这里我们定义一个比较常用的页面的标题栏布局。
title_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:paddingLeft="20dp" android:paddingRight="20dp" android:layout_width="match_parent" android:layout_height="47dp">
<ImageView android:clickable="true" android:layout_centerVertical="true" android:src="@android:drawable/btn_star" android:layout_alignParentLeft="true" android:id="@+id/leftImage" android:scaleType="fitXY" android:layout_width="30dp" android:layout_height="30dp" />
<TextView android:gravity="center" android:layout_toLeftOf="@+id/rightFrame" android:ellipsize="end" android:singleLine="true" android:id="@+id/title" android:layout_toRightOf="@+id/leftImage" android:layout_centerInParent="true" android:textColor="@android:color/white" android:textSize="17sp" android:text="标题" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<FrameLayout android:layout_centerVertical="true" android:layout_alignParentRight="true" android:id="@+id/rightFrame" android:layout_width="wrap_content" android:layout_height="wrap_content">
<ImageView android:clickable="true" android:visibility="gone" android:src="@android:drawable/btn_star" android:id="@+id/rightImage" android:scaleType="fitXY" android:layout_width="30dp" android:layout_height="30dp" />
<TextView android:clickable="true" android:text="完成" android:textSize="15sp" android:textColor="@android:color/white" android:id="@+id/rightText" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</FrameLayout>
</RelativeLayout>
大概就是这个样子:
左边是一张图片,中间是标题名称,右边有可能是图片也有可能是文字。
下面我们把这个加入到我们的自定义控件中去,自定义控件也是自定义View啊,首先还是写属性吧
<!--自定义组合控件属性-->
<declare-styleable name="CustomCombinationWiget">
<attr name="leftImage" format="reference"></attr>
<attr name="leftImage_width" format="dimension"></attr>
<attr name="leftImage_height" format="dimension"></attr>
<attr name="leftImageVisible">
<enum name="visible" value="1"></enum>
<enum name="gone" value="0"></enum>
</attr>
<attr name="title" format="string"></attr>
<attr name="titleSize" format="dimension"></attr>
<attr name="titleColor" format="color"></attr>
<attr name="titleVisible">
<enum name="visible" value="1"></enum>
<enum name="gone" value="0"></enum>
</attr>
<attr name="rightImage" format="reference"></attr>
<attr name="rightImage_height" format="dimension"></attr>
<attr name="rightImage_width" format="dimension"></attr>
<attr name="rightImageVisible">
<enum name="visible" value="1"></enum>
<enum name="gone" value="0"></enum>
</attr>
<attr name="rightText" format="string"></attr>
<attr name="rightTextSize" format="dimension"></attr>
<attr name="rightTextColor" format="color"></attr>
<attr name="rightTextVisible">
<enum name="visible" value="1"></enum>
<enum name="gone" value="0"></enum>
</attr>
</declare-styleable>
这里面我写的属性比较多,写的都是可能遇到的,当然你可以根据自己的项目需求适量的删减,一般不需要这么多的。
下面看我们的最重要的代码:
//由于我们需要把我们的布局放到一个容器里面,这里就使用最简单的布局容器FramLayout
public class CustomCombinationWiget extends FrameLayout {
private int lImage,rImage;//左右imageView
private int lheight,lwidth,lVisible,rheight,rwidth,rTextVisible,rImageVisible,cVisible,rTextSize,cTextSize;
private String cText,rText;//textview的文字
private int cColor,rColor;
private TextView mtitle,mrightText;
private ImageView mlImage,mrImage;
public CustomCombinationWiget(Context context) {
this(context, null);
}
public CustomCombinationWiget(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomCombinationWiget(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.CustomCombinationWiget,defStyleAttr,0);
lImage= typedArray.getResourceId(R.styleable.CustomCombinationWiget_leftImage,0);
rImage=typedArray.getResourceId(R.styleable.CustomCombinationWiget_rightImage, 0);
lheight=typedArray.getDimensionPixelSize(R.styleable.CustomCombinationWiget_leftImage_height,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics()));
lwidth=typedArray.getDimensionPixelSize(R.styleable.CustomCombinationWiget_leftImage_width,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics()));
lVisible=typedArray.getInt(R.styleable.CustomCombinationWiget_leftImageVisible, 1);
rImageVisible=typedArray.getInt(R.styleable.CustomCombinationWiget_rightImageVisible, 1);
rTextVisible=typedArray.getInt(R.styleable.CustomCombinationWiget_rightTextVisible, 0);
cVisible=typedArray.getInt(R.styleable.CustomCombinationWiget_titleVisible, 1);
rheight=typedArray.getDimensionPixelSize(R.styleable.CustomCombinationWiget_rightImage_height,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics()));
rwidth=typedArray.getDimensionPixelSize(R.styleable.CustomCombinationWiget_rightImage_width,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics()));
rTextSize=typedArray.getDimensionPixelSize(R.styleable.CustomCombinationWiget_rightTextSize,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 17, getResources().getDisplayMetrics()));
cTextSize=typedArray.getDimensionPixelSize(R.styleable.CustomCombinationWiget_titleSize,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 19, getResources().getDisplayMetrics()));
cColor=typedArray.getColor(R.styleable.CustomCombinationWiget_titleColor, getResources().getColor(android.R.color.white));
rColor=typedArray.getColor(R.styleable.CustomCombinationWiget_rightTextColor, getResources().getColor(android.R.color.white));
cText=typedArray.getString(R.styleable.CustomCombinationWiget_title);
rText=typedArray.getString(R.styleable.CustomCombinationWiget_rightText);
typedArray.recycle();
initvView(context);
}
private void initvView(Context context) {
LayoutInflater.from(context).inflate(R.layout.title_layout, this, true);
mtitle=(TextView)findViewById(R.id.title);
mrightText=(TextView)findViewById(R.id.rightText);
mlImage=(ImageView)findViewById(R.id.leftImage);
mrImage=(ImageView)findViewById(R.id.rightImage);
//初始化标题的属性
if(!TextUtils.isEmpty(cText)){
mtitle.setText(cText);
}
mtitle.setTextColor(cColor);
mtitle.setTextSize(cTextSize);
//初始化左控件
mlImage.setImageResource(lImage);
mlImage.getLayoutParams().height=lheight;
mlImage.getLayoutParams().width=lwidth;
mlImage.setLayoutParams(mlImage.getLayoutParams());
setVisible(mlImage, lVisible);
mlImage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
}
});
//初始化右图片
setVisible(mrImage, rImageVisible);
if(mrImage.getVisibility()== View.VISIBLE) {
mrImage.setImageResource(rImage);
mrImage.getLayoutParams().width = rwidth;
mrImage.getLayoutParams().height = rheight;
mrImage.setLayoutParams(mrImage.getLayoutParams());
}
//初始化
setVisible(mrightText, rTextVisible);
if(mrightText.getVisibility()== View.VISIBLE){
if(TextUtils.isEmpty(rText)) {
mrightText.setText(rText);
}
mrightText.setTextSize(rTextSize);
mrightText.setTextColor(rColor);
}
}
/*** * 为组合控件设置点击事件 * @param combinationListener */
public void setCombinationListener(final Combinationlistener combinationListener){
mlImage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
combinationListener.leftImageListener();
}
});
mrightText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
combinationListener.rightTextListener();
}
});
mrImage.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
combinationListener.rightImageListener();
}
});
}
//设置控件是否可见
private void setVisible(View view,int value){
if(value==1){
view.setVisibility(View.VISIBLE);
}else {
view.setVisibility(View.GONE);
}
}
//暴露出来的点击事件接口
public interface Combinationlistener{
void leftImageListener();
void rightImageListener();
void rightTextListener();
}
}
上面的代码应该比较好理解,可能不好理解的是
LayoutInflater.from(context).inflate(R.layout.title_layout, this, true);
mtitle=(TextView)findViewById(R.id.title);
mrightText=(TextView)findViewById(R.id.rightText);
mlImage=(ImageView)findViewById(R.id.leftImage);
mrImage=(ImageView)findViewById(R.id.rightImage);
关于inflate的用法:
可以看一下这篇文章:
inflate探究
初始化了控件属性和控件之后,就是给我们的控件设置监听事件了,我们自定义接口,把接口暴露给调用者。
布局中的使用
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
tools:context=".MainActivity">
<com.example.yinwei.myapplication.view.CustomCombinationWiget
android:id="@+id/cw"
android:background="@android:color/holo_red_light"
app:leftImage="@android:drawable/btn_plus"
app:rightImageVisible="visible"
app:rightText="@string/hello_world"
app:title="@string/hello_world"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
看在activity里面的使用:
public class MainActivity extends Activity {
private CustomCombinationWiget cw;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cw=(CustomCombinationWiget)findViewById(R.id.cw);
cw.setCombinationListener(new CustomCombinationWiget.Combinationlistener() {
@Override
public void leftImageListener() {
Toast.makeText(MainActivity.this,"左图片按钮被点击了",Toast.LENGTH_SHORT).show();
}
@Override
public void rightImageListener() {
Toast.makeText(MainActivity.this,"右图片按钮被点击了",Toast.LENGTH_SHORT).show();
}
@Override
public void rightTextListener() {
Toast.makeText(MainActivity.this,"右文字按钮被点击了",Toast.LENGTH_SHORT).show();
}
});
}
}
效果图: