Android 自定义view第二弹——组合控件
来源:互联网 发布:thinkphp nginx 配置 编辑:程序博客网 时间:2024/04/30 05:55
概述:本篇为自定义控件的三种实现方式第一种—组合控件,在此篇中,我将以一个例子的形式来展现组合控件的实现方式。
一组合控件的定义
自定义组合控件一般来说都是以ViewGroup及其子类(LinearLayout、RelativeLayout、FrameLayout等)为主,内部嵌套其他控件,来组合成一个新的控件,实现一些特定的需要,可以是代码简化,结构清晰,重用性较高。通常来说,我们会实现定义好一个Layout.xml文件,然后让我们的自定义控件去加载此xml,并获取子控件,然后设置属性(可以通过代码,也可以从资源文件中加载)、添加事件。
二 自定义组合控件注意要点:
1.加载xml文件是在构造方法中完成的,通过调用inflate(R.layout.my_layout,this,true),注意第二个和第三个参数;
2.如果需要从资源文件中加载自定义的属性,则必须重写Constructor(Context context, AttributeSet attrs)此构造方法,属性是定义在attrs.xml中的;
3.获取子控件对象,可以在构造方法中获取,也可以重写onFinishInflate()方法来获取,个人建议采用第二种,可以保证控件已经完全加载好了;
4.添加事件可以直接在控件中写,不过考虑到扩展性及复用性,建议对外暴露接口。
三 一个栗子
1 栗子说明
在很多项目中,我们都会用到app标题栏,几乎每个页面的形式都一样,左边 中间 右边 。但在每个页面中 左边 中间 右边的内容又是不一样的。如果我们在每个页面的布局中重新写的话,将是一个繁琐的工作。如果我们将所有的形式都融合在一个布局用 include来引用时 每个页面的逻辑不一样 要让不用的控件来显示和隐藏 就会显得特别的麻烦。所以在这里我们用自定义view的组合控件的方式简化我们的代码实现同样的效果。
2 栗子实现步骤
① 继承
自定义组合控件必须继承ViewGroup或者其子类。 CustomTitleBar extends RelativeLayout
在这里我们继承的是RelativeLayout 至于为什么继承RelativeLayout 我会在后面说明。先来看看我们的构造方法
public CustomTitleBar(Context context) { this(context, null); } public CustomTitleBar(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomTitleBar(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs, defStyleAttr); }
一个参数的构造方法 调 二个参数的构造方法 两个参数的构造方法 调三个参数的构造方法 在三个参数的构造方法中 有一个init()的方法初始化 传入了 上下文 属性集合 默认样式
② 自定义属性
在res文件夹下的value文件中 生成 attrs文件
声明一组属性:
使用来定义一个属性集合,name就是属性集合的名字,这个名字一定要起的见名知意。
<declare-styleable name="CustomTitleBar"> <!--添加属性--> </declare-styleable>
然后就是定义属性值了,通过 方式定义属性值,属性名字同样也要起的见名知意,format表示这个属性的值的类型,类型有以下几种:
reference:引用资源string:字符串Color:颜色boolean:布尔值dimension:尺寸值float:浮点型integer:整型fraction:百分数enum:枚举类型flag:位或运算
栗子的属性集合如下
<resources> <declare-styleable name="CustomTitleBar"> <attr name="TitleBar_background_color" format="color|reference" /> <!-- 左边 --> <attr name="TitleBar_left_text" format="string|reference" /> <attr name="TitleBar_left_text_size" format="dimension|reference" /> <attr name="TitleBar_left_text_color" format="color|reference" /> <attr name="TitleBar_left_Drawable" format="reference" /> <!-- 中间--> <attr name="TitleBar_center_text" format="string|reference" /> <attr name="TitleBar_center_text_size" format="dimension|reference" /> <attr name="TitleBar_center_text_color" format="color|reference" /> <attr name="TitleBar_center_Drawable" format="reference" /> <!-- 右边--> <attr name="TitleBar_right_text" format="string|reference" /> <attr name="TitleBar_right_text_size" format="dimension|reference" /> <attr name="TitleBar_right_text_color" format="color|reference" /> <attr name="TitleBar_right_Drawable" format="reference" /> </declare-styleable></resources>
③ 获取自定义属性
init()方法中 首先 初始化布局:
//初始化布局LayoutInflater.from(getContext()).inflate(R.layout.layout_custom_titlebar, this, true);
我们来看看我们的布局文件
<merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/left_tv" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:background="?android:attr/selectableItemBackground" android:gravity="center_vertical|left" android:minWidth="50dp" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="10dp" android:singleLine="true" android:textColor="@android:color/white" android:textSize="16sp" /> <TextView android:id="@+id/center_tv" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_centerHorizontal="true" android:layout_marginLeft="70dp" android:layout_marginRight="70dp" android:gravity="center_vertical" android:singleLine="true" android:text="" android:textColor="@android:color/white" android:textSize="18sp" /> <TextView android:id="@+id/right_tv" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:background="?android:attr/selectableItemBackground" android:gravity="center_vertical|right" android:minWidth="50dp" android:paddingLeft="10dp" android:paddingRight="@dimen/activity_horizontal_margin" android:singleLine="true" android:text="" android:textColor="@android:color/white" android:textSize="16sp" /></merge>
可以看到在布局文件中 我们用到了 merge标签 不知道什么意思和用法的同学请自行Google(我鄙视百度) 因为为了 更好的控制布局 我们继承了RelativeLayout 也就是 我们把merge标签里的控件直接放在了RelativeLayout中 所以 在merger标签中的 控件 的属性 要按RelativeLayout布局来使用 比如
<TextView android:id="@+id/left_tv" android:layout_width="wrap_content" android:layout_height="match_parent" **android:layout_alignParentLeft="true"** android:background="?android:attr/selectableItemBackground" **android:gravity="center_vertical|left"** android:minWidth="50dp" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="10dp" android:singleLine="true" android:textColor="@android:color/white" android:textSize="16sp" />
//获取自定义属性的集合TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomTitleBar, defStyleAttr, 0);//背景颜色mBackgroundColor = array.getColor(R.styleable.CustomTitleBar_TitleBar_background_color, Color.WHITE);//左边mLeftText = array.getString(R.styleable.CustomTitleBar_TitleBar_left_text);mLeftTextColor = array.getColor(R.styleable.CustomTitleBar_TitleBar_left_text_color, Color.BLACK);mLeftTextSize = array.getDimension(R.styleable.CustomTitleBar_TitleBar_left_text_size, sp2px(16));mLeftDrawable = array.getDrawable(R.styleable.CustomTitleBar_TitleBar_left_Drawable);//中间mCenterText = array.getString(R.styleable.CustomTitleBar_TitleBar_center_text);mCenterTextColor = array.getColor(R.styleable.CustomTitleBar_TitleBar_center_text_color, Color.WHITE);mCenterTextSize = array.getDimension(R.styleable.CustomTitleBar_TitleBar_center_text_size, sp2px(18));mCenterDrawable = array.getDrawable(R.styleable.CustomTitleBar_TitleBar_center_Drawable);//右边mRightText = array.getString(R.styleable.CustomTitleBar_TitleBar_right_text);mRightTextColor = array.getColor(R.styleable.CustomTitleBar_TitleBar_right_text_color, Color.WHITE);mRightTextSize = array.getDimension(R.styleable.CustomTitleBar_TitleBar_right_text_size, sp2px(16));mRightDrawable = array.getDrawable(R.styleable.CustomTitleBar_TitleBar_right_Drawable);//释放资源 必须添加array.recycle();
④ 获取控件 设置空间属性
/** * 此方法中 代表布局一定初始化完成 不存在空指针问题 */ @Override protected void onFinishInflate() { super.onFinishInflate(); tvLeft = (TextView) findViewById(R.id.left_tv); tvCenter = (TextView) findViewById(R.id.center_tv); tvRight = (TextView) findViewById(R.id.right_tv); //设置背景颜色 setBackgroundColor(mBackgroundColor); //设置左边 setLeft(mLeftText, mLeftTextColor, mLeftTextSize, mLeftDrawable); //设置中间 setCenter(mCenterText, mCenterTextColor, mCenterTextSize, mCenterDrawable); //设置右边 setRight(mRightText, mRightTextColor, mRightTextSize, mRightDrawable); } private void setLeft(CharSequence leftText, int leftTextColor, float leftTextSize, Drawable leftDrawable) { if (leftDrawable != null) { leftDrawable.setBounds(0, 0, leftDrawable.getMinimumWidth(), leftDrawable.getMinimumHeight()); tvLeft.setCompoundDrawables(leftDrawable, null, null, null); } tvLeft.setText(leftText); tvLeft.setTextSize(TypedValue.COMPLEX_UNIT_PX, leftTextSize); tvLeft.setTextColor(leftTextColor); tvLeft.setClickable(!TextUtils.isEmpty(leftText) || leftDrawable != null); } private void setCenter(CharSequence centerText, int centerTextColor, float centerTextSize, Drawable centerDrawable) { if (centerDrawable != null) { centerDrawable.setBounds(0, 0, centerDrawable.getMinimumWidth(), centerDrawable.getMinimumHeight()); tvCenter.setCompoundDrawables(centerDrawable, null, null, null); } tvCenter.setText(centerText); tvCenter.setTextSize(TypedValue.COMPLEX_UNIT_PX, centerTextSize); tvCenter.setTextColor(centerTextColor); tvCenter.setClickable(!TextUtils.isEmpty(centerText) || centerDrawable != null); } private void setRight(CharSequence rightText, int rightTextColor, float rightTextSize, Drawable rightDrawable) { if (rightDrawable != null) { rightDrawable.setBounds(0, 0, rightDrawable.getMinimumWidth(), rightDrawable.getMinimumHeight()); tvRight.setCompoundDrawables(rightDrawable, null, null, null); } tvRight.setText(rightText); tvRight.setTextSize(TypedValue.COMPLEX_UNIT_PX, rightTextSize); tvRight.setTextColor(rightTextColor); tvRight.setClickable(!TextUtils.isEmpty(rightText) || rightDrawable != null); } /** * 将空间暴露出去 提供给外界 * @return */ public TextView getTvLeft() { return tvLeft; } /** * 将空间暴露出去 提供给外界 * @return */ public TextView getTvCenter() { return tvCenter; } /** * 将空间暴露出去 提供给外界 * @return */ public TextView getTvRight() { return tvRight; } //一些工具方法 protected int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } protected int sp2px(int sp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); }
⑤ 引用自定义控件
千万不要忘了在跟节点 标记命名空间
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" ***xmlns:app="http://schemas.android.com/apk/res-auto"*** android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.jack.customtitleview.customView.CustomTitleBar android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="48dp" ***app:TitleBar_background_color="#00ff00" app:TitleBar_left_text="中国"***/> <com.jack.customtitleview.customView.CustomTitleBar android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="48dp" ***app:TitleBar_background_color="#12b7f5"*** ***app:TitleBar_left_Drawable="@drawable/ic_back_gray" app:TitleBar_left_text="中国"*** ***app:TitleBar_right_Drawable="@drawable/ic_msg_gray"*** /> <com.jack.customtitleview.customView.CustomTitleBar android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="48dp" ***app:TitleBar_background_color="#12b7f5"*** ***app:TitleBar_left_Drawable="@drawable/ic_back_gray" app:TitleBar_right_Drawable="@drawable/ic_msg_gray"***> ***<include layout="@layout/layout_search_view" />*** </com.jack.customtitleview.customView.CustomTitleBar></LinearLayout>
因为 我们继承的RelativeLayout 也是一个容器 所以可以引用 include
四 效果显示
源码地址 源码地址
- Android 自定义view第二弹——组合控件
- Android自定义view——组合控件
- android自定义View——组合控件
- android 自定义View研究(三) — 自定义组合控件
- Android 自定义组合控件View
- android:自定义view--组合控件
- Android自定义View 自定义组合控件
- Android自定义View----1. 自定义组合控件
- Android学习自定义View(三)——自绘控件和组合控件
- Android进阶——自定义View之重写ViewGroup组合系统控件实现自定义ToolBar模板
- Android自定义view组合控件解析
- Android自定义控件——组合控件
- 自定义View组合控件
- Android学习摘记——简单的自定义View(组合控件)
- Android进阶——自定义View之组合系统控件实现水珠形状的ItemView
- 自定义View---自定义组合控件
- Android自定义控件——自定义组合控件
- Android自定义组合控件——简单明了
- 路
- 包的管理
- [Oracle] 循环的几种方式
- 花样灯
- 为ios工程添加 .dylib库 的方法,libz.dylib libsqlite3.dylib等等
- Android 自定义view第二弹——组合控件
- android studio主题设置
- SpringBoot @EnableAutoConfiguration原理
- 后缀数组(长度不小于k的公共子串的个数)
- B. One Bomb
- sockaddr_in , sockaddr , in_addr区别Socket编程函数集(非常有用)
- 【Unity】SQLite在Unity中的使用-思维导图
- /dev/mem可没那么简单
- php协程(Coroutine)学习笔记