自定义ViewGroup/组合控件
一、重复布局的使用
在开发中,经常遇到在App中多个地方使用相同的布局的场景,如自己的actionbar或者加载动画等。实现的方法有:
-
最直观的,在每个地方用xml写出各自的布局;
-
使用include标签实现layout文件复用
首先创建一个layout的xml文件,在其中编写需要重复使用的布局;在用到的地方使用< include>标签来实现复用。< include layout="@layout/layout_file" />
-
通过自定义ViewGroup实现
是最常用的方案,易于维护且实现难度不大,对于提高代码复用、降低布局文件与activity耦合都有着重要的作用。
二、自定义ViewGroup实现
下面以一个实际需求为例:在桌面应用中通过自定义ViewGroup实现一个Dock栏。
2.1 编写布局文件
新建一个layout文件,编写自定义viewgroup包含的内容以及样式,一般使用RelativeLayout或LinearLayout中包含系统控件的方式实现;
若要在自定义ViewGroup中动态加载,也可以不需要布局文件,通过继承RelativeLayout或LinearLayout,使用addView()方法动态添加子view,并使用LayoutParam设置子view的布局参数,如大小、左右缩进等;
如下向线性布局中动态添加一个ImageView:
LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(iconSize,iconSize);
params1.leftMargin = pads;
params1.rightMargin=pads;
params1.topMargin=(iconPadTop);
params1.bottomMargin=(iconPadTop);
ImageView iv=new ImageView(ctx);
iv.setImageDrawable(apps.get(i).getAppIcon());
iv.setOnClickListener(this);
this.addView(iv,i,params1); V.iewGroup类继承LinearLayout
2.2 添加自定义属性.
与上一篇添加自定义属性方法相同,在attrs.xml中声明一个< declare-stylable>并添加属性;以下为Dock栏设置了背景色、图标大小,及与上下的距离。
< declare-styleable name="Dock">
< attr name="iconPaddingTop" format="dimension"/>
< attr name="dockBacgroundColor" format="color"/>
<attr name="dockIconSize" format="dimension"/>
</declare-styleable>
2.3 创建ViewGroup类并继承合适的布局
考虑到Dock栏的需求,需要将添加的应用图标横向的排列,故继承LinearLayout实现,并在构造方法中设置方向为横行;
2.4 编写ViewGroup方法
实现类中的各种方法;
2.4.1 构造方法
public class Dock extends LinearLayout implements View.OnClickListener,View.OnTouchListener {
public Dock(Context context) {
this(context,null);
}
public Dock(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public Dock(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
ctx=context;
setOrientation(LinearLayout.HORIZONTAL);
}
2.4.2 获取自定义属性
与自定义View相同,使用TypedArray获取自定义属性;下面的代码中计算了图标显示的像素大小,并通过pad值计算Dock的高度;
private void initAttrs(Context context, AttributeSet attrs){
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); //getSystemService(Context.WINDOW_SERVICE).getDefaultDisplay().getMetrics(displayMetrics);
density =displayMetrics.density;
dockWidth=displayMetrics.widthPixels;
TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.Dock);
iconSize=(int)ta.getDimension(R.styleable.Dock_dockIconSize,dp2px(context,60));
iconPadTop=(int)ta.getDimension(R.styleable.Dock_iconPaddingTop,dp2px(context,15));
dockHeight=iconSize; //(int)ta.getDimension(R.styleable.Dock_dockHeight,dp2px(context,100));
dockBgColor=ta.getColor(R.styleable.Dock_dockBacgroundColor, Color.parseColor("#f8f8f8"));
ta.recycle();
}
2.4.3 初始化View
设置Dock栏背景,并添加图标;
private void initView(Context context){
setBackgroundColor(dockBgColor);
for(int i=0;i<apps.size();i++)
{
LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(iconSize,iconSize); //View大小
params1.leftMargin = pads; //设置图标添加位置
params1.rightMargin=pads;
params1.topMargin=(iconPadTop);
params1.bottomMargin=(iconPadTop);
ImageView iv=new ImageView(ctx);
iv.setImageDrawable(apps.get(i).getAppIcon());
this.addView(iv,i,params1);
}
}
2.4.4 其他业务需求方法
点击图标打开应用等操作;
2.5 在布局中引用该控件
通过实现上面的方法,完成了一个自定义ViewGroup的桌面Dock栏自定义Dock栏开发;
实现以后,就可以在主activity中引用此控件并设置属性,如下:
<com.space.lisktop.Dock
android:id="@+id/mydock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:iconPaddingTop="8dp"
app:dockIconSize="60dp"
app:dockBacgroundColor="#eeeeee"/>