在最近几天,经常被他人问道Android自定义组件的知识,心里有个大概的框架,但有时有语言描述时,感觉却无从开口。查询资料时感觉有点杂乱,所以今天把自定义组件的资料整理一下。
自定义组件是在Android开发经常用到,当系统预定义的组件无法满足开发的需求时,或者开发过程中存在类似组件复用时,就可以将其复用的组件自定义成为模板,减少代码的冗余,提高代码的复用。
自定义组件可以分为两种:一种是自定义View,另一种则就是自定义ViewGroup.。
这两种自定义组件的流程大指差不多,但其细节却存在很大的异同。下面我简单的书写一下自定义组件的流程
(1)根据需求确定自定义组件的类型
(2)根据所需的自定义组件的类型及其开发的需求确定自定义属性
(3)根据需求重新 onMeasure,onLayout,onDraw方法。注意:防止wrap_content和padding失效
(4)如果是自定义ViewGroup,则需要防止滑动冲突。
上述仅是提供自定义组件的开发过程的参考,其中防止wrap_content和padding失效涉及到View的工作流程,防止滑动冲突涉及到时间分发机制。我将在后续详细讲解其知识。下面我将通过一种小demo来总结一下上述的知识。
此demo为自定义ViewGroup,也成为自定义的组合模式:
其最终的效果如下:
其实现步骤如下
1、在res目录下的values目录创建自定义属性文件attrs
2、实现自定义属性,其中自定义的属性为左边Button的背景,字体颜色,字体大小;右边Button的背景,字体颜色,字体大小,中
间title的背景,字体颜色,字体大小:源码如下:
<?xml version="1.0" encoding="utf-8"?> <!--设置自定义组件的属性--> <resources> <declare-styleable name="topBar"> <attr name="titleText" format="string"></attr> <attr name="titleTextSize" format="dimension"></attr> <attr name="titleColor" format="color"></attr> <attr name="titleBackground" format="color|reference"></attr> <attr name="leftText" format="string"></attr> <attr name="leftTextColor" format="color"></attr> <attr name="leftTextSize" format="dimension"></attr> <attr name="leftBackground" format="color|reference"></attr> <attr name="rightText" format="string"></attr> <attr name="rightTextSize" format="dimension"></attr> <attr name="rightTextColor" format="color"></attr> <attr name="rightBackground" format="color|dimension"></attr> </declare-styleable> </resources>
3、自定义ViewGroup,实现其构造函数,关联自定义属性,源码如下:
1)自定义组件的类名
public class TopBar extends RelativeLayout
2)自定义组件的所关联属性的成员变量
private String titleText; private int titleTextSize; private int titleColor; private Drawable titleBackground; private String leftText; private int leftTextColor; private int leftTextSize; private Drawable leftBackground; private String rightText; private int rightTextColor; private int rightTextSize; private Drawable rightBackground;
3)重写自定义组件的构造函数,关联自定义属性private Button leftButton; private Button rightButton; private TextView titleTextView; private LayoutParams leftLayoutParams; private LayoutParams rightLayoutParams; private LayoutParams titleLayoutParams; private TopBarClickListener listener;
/** * 实现TopbBar的构造函数用于关联自定义属性 */ public TopBar(Context context, AttributeSet attrs) { super(context, attrs); relevanceAttr(context, attrs); relevanceView(context, attrs); topBarClickListener(); }
/** * @param context * @param attrs * @return void * 关联自定义属性 */ private void relevanceAttr(Context context, AttributeSet attrs) { /** * attrs 自定义的资源文件 * * * R.styleable.topBar 自定义的属性资源名 * * * 关联自定义属性文件,将自定义属性保存在该集合里面 * */ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.topBar); titleText = ta.getString(R.styleable.topBar_titleText); titleTextSize = (int) ta.getDimension(R.styleable.topBar_titleTextSize, 0); titleColor = ta.getColor(R.styleable.topBar_titleColor, 0); titleBackground = ta.getDrawable(R.styleable.topBar_titleBackground); leftText = ta.getString(R.styleable.topBar_leftText); leftTextColor = ta.getColor(R.styleable.topBar_leftTextColor, 0); leftTextSize = (int) ta.getDimension(R.styleable.topBar_leftTextSize, 0); leftBackground = ta.getDrawable(R.styleable.topBar_leftBackground); rightText = ta.getString(R.styleable.topBar_rightText); rightTextColor = ta.getColor(R.styleable.topBar_rightTextColor, 0); rightTextSize = (int) ta.getDimension(R.styleable.topBar_rightTextSize, 0); rightBackground = ta.getDrawable(R.styleable.topBar_rightBackground); ta.recycle();//手动回收ta } /** * @param context * @param attrs * @return void * <p/> * 将自定义的属性与组件关联 */ private void relevanceView(Context context, AttributeSet attrs) { leftButton = new Button(context); rightButton = new Button(context); titleTextView = new TextView(context); titleTextView.setText(titleText); titleTextView.setTextSize(titleTextSize); titleTextView.setTextColor(titleColor); titleTextView.setBackground(titleBackground); titleTextView.setGravity(Gravity.CENTER); leftButton.setText(leftText); leftButton.setTextColor(leftTextColor); leftButton.setTextSize(leftTextSize); leftButton.setBackground(leftBackground); rightButton.setText(rightText); rightButton.setTextColor(rightTextColor); rightButton.setTextSize(rightTextSize); rightButton.setBackground(rightBackground); setBackgroundColor(0x59563); //设置leftButton的width和height leftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); //让leftButton居左对齐 leftLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE); this.addView(leftButton, leftLayoutParams); //设置rightButton的width和height rightLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); //使rightButton居右对齐 rightLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE); this.addView(rightButton, rightLayoutParams); //设置title的width和height titleLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); //使titleTextView居中对齐 titleLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE); this.addView(titleTextView, titleLayoutParams); }
4)运用接口回调机制,提供事件监听
/** * 该接口用于外部点击事件 */ public interface TopBarClickListener { public void setLeftOnClickListener(); public void setRightOnClickListener(); }
/** * @param listener * @return void * 将接口暴露给外部,提供外部访问 */ public void setOnClickListener(TopBarClickListener listener) { this.listener = listener; }
/** * @param * @return void * <p/> * 设置接口回调 */ private void topBarClickListener() { leftButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listener.setLeftOnClickListener(); } }); rightButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { listener.setRightOnClickListener(); } }); }
5)设置左右Button是否显示
/** * @param leftVisibility * @param rightVisibility * @return void * 设置左右Button是否显示 */ public void setVisibility(boolean leftVisibility, boolean rightVisibility) { if (!leftVisibility && !rightVisibility) { leftButton.setVisibility(GONE); rightButton.setVisibility(GONE); } else if (leftVisibility && !rightVisibility) { leftButton.setVisibility(VISIBLE); rightButton.setVisibility(GONE); } else if (!leftVisibility && rightVisibility) { leftButton.setVisibility(GONE); rightButton.setVisibility(VISIBLE); } else { leftButton.setVisibility(VISIBLE); rightButton.setVisibility(VISIBLE); } }
6)在activity_content的xml文布局该自定义的组件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:custom="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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".MainActivity" tools:showIn="@layout/activity_main"> <com.yongxiang.sm.customview.TopBar android:id="@+id/top" android:layout_width="match_parent" android:layout_height="50dp" custom:leftBackground="#e78df2" custom:leftText="back" custom:leftTextColor="#FFFFFF" custom:leftTextSize="12sp" custom:rightBackground="#e78df2" custom:rightText="more" custom:rightTextColor="#FFFFFF" custom:rightTextSize="12sp" custom:titleBackground="#64f2a0" custom:titleColor="#456321" custom:titleText="title" custom:titleTextSize="16sp" ></com.yongxiang.sm.customview.TopBar> </RelativeLayout>
public class MainActivity extends AppCompatActivity { private TopBar topBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initEvent(); initVisiblity(); } /** * @param * @return void * 初始化组件 */ private void initView() { this.topBar = (TopBar) findViewById(R.id.top); } /** * @param * @return void * <p/> * 初始化事件监听 */ private void initEvent() { this.topBar.setOnClickListener(new TopBar.TopBarClickListener() { @Override public void setLeftOnClickListener() { Toast.makeText(MainActivity.this, "left Button OnClick!", Toast.LENGTH_SHORT).show(); } @Override public void setRightOnClickListener() { Toast.makeText(MainActivity.this, "right Button OnClick!", Toast.LENGTH_SHORT).show(); } }); } /** * @param * @return void * <p/> * 设置左右Button是否显示 */ private void initVisiblity() { topBar.setVisibility(true, true); } }