热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

自定义组合控件实现布局重用

YoucouldcombineagroupofViewcomponentsintoanewsinglecomponent,perhapstomakesomethinglikeaCo

You could combine a group of View components into a new single component, perhaps to make something like a ComboBox (a combination of popup list and free entry text field), a dual-pane selector control (a left and right pane with a list in each where you can re-assign which item is in which list), and so on.

背景:

android开发中对于一些重复的布局。通常我们的处理方式不外乎以下三种

1.直接复制粘贴已有布局代码

2.将重复xml布局抽离出来,再利用include和merge标签来使用该布局(merge主要用于优化性能)

3.自定义组合控件

优缺点:

第一种方式优缺点很明显,虽然简单,快捷。但是当重复的布局比较复杂且重复的次数比较多的时候会使得布局文件很臃肿,不利于阅读和修改。
第二种方式可以应付大部分布局重用情况,但也有局限性,比如要实现下图一效果,在同一个布局文件中包含多个复用布局(暂且叫做卡片布局),使用include标签显然不行,无法设置每个卡片上的图片和文字。这个时候第三种方式组合控件就派上用场了。

《自定义组合控件实现布局重用》 图一.png

自定义组合控件:

step1:自定义布局文件(卡片布局)


android:layout_
android:layout_
android:gravity="center"
android:orientation="vertical" >
android:id="@+id/imageview"
android:layout_
android:layout_
android:layout_gravity="center"
android:scaleType="centerInside"
android:src="@mipmap/ic_launcher" />
android:id="@+id/text"
android:layout_
android:layout_
android:gravity="center"
android:text="卡片文字" />

注释:

这个很简单,就是一个上面图片下面文字的简单布局

step2: 自定义属性



//文字内容
//文字尺寸
//文字颜色
//文字顶部margin
//图片资源
//imageView的宽度
//imageView的高度

注释:

自定义属性的多少取决于控件的复杂程度以及你想这个控件具备的扩展性强弱,比如这个卡片布局,如果你认为只有这一个页面会用到的话,只定义图片资源和文字内容两个属性,其它的属性在上面的step1中写死,也能达到图一的效果,但这就跟我们布局重用的初衷相违背了。
这里总共定义了7种属性,对于一般情况应该是够用了。当然你也可以继续扩展,比如添加图片是否圆角显示,圆角半径等其它属性来扩展其功能。
对于不同类型的属性,值的类型也不一样,比如文字内容是String类型,文字尺寸这个属性应该是dimension。Android提供了丰富的值类型供我们选择:reference,color,boolean,dimension,float,integer,string,fraction,enum,flag
具体用法可参考这里:Android自定义属性,format详解

step3:代码实现

public class CardLinearLayout extends LinearLayout {
private ImageView mImage;
private TextView mTextView;
private String mText = ""; //文字内容
private int mTextColor; //文字颜色
private int mTextSize ; //文字尺寸
private int mImageWidth ; //imageView的宽度
private int mImageHeight ; //imageView的高度
private Drawable mDrawable; //图片资源
private int mTextMarginTop; //文字顶部margin
public CardLinearLayout(Context context) {
this(context, null);
}
public CardLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode()) {//解决可视化编辑器无法识别自定义控件的问题
// 在构造函数中将Xml中定义的布局解析出来。
LayoutInflater.from(context).inflate(R.layout.card_linealayout, this, true);
mImage = (ImageView) findViewById(R.id.imageview);
mTextView = (TextView) findViewById(R.id.text);
}
//获取在下面step4引用布局时在XML文件中定义的属性值
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CardLinearLayout);
mText = a.getString(R.styleable.CardLinearLayout_card_text);
mTextColor = a.getColor(R.styleable.CardLinearLayout_card_text_color, Color.WHITE);
mTextSize = a.getDimensionPixelOffset(R.styleable.CardLinearLayout_card_text_size, 12);
mTextMarginTop = a.getDimensionPixelOffset(R.styleable.CardLinearLayout_card_text_margin_top, 0);
mImageWidth = a.getDimensionPixelOffset(R.styleable.CardLinearLayout_card_image_width, 100);
mImageHeight = a.getDimensionPixelOffset(R.styleable.CardLinearLayout_card_image_height, 100);
mDrawable = a.getDrawable(R.styleable.CardLinearLayout_card_image_src);
//将获取到的值设置到相应位置
if (!isInEditMode()) { //解决可视化编辑器无法识别自定义控件的问题
mTextView.setText(mText);
mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
Log.i("CardLinearLayout", "====mTextSize=" + mTextSize);
mTextView.setTextColor(mTextColor);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(0, mTextMarginTop, 0, 0);
mTextView.setLayoutParams(layoutParams);
mImage.setImageDrawable(mDrawable);
LayoutParams imageLayoutParams = new LayoutParams(mImageWidth, mImageHeight);
imageLayoutParams.gravity = Gravity.CENTER;
mImage.setLayoutParams(imageLayoutParams);
}
a.recycle(); //这个别忘了
}
/**
* 在代码中设置卡片的图片
* @param imageId 图片id
*/
public void setImageResource(int imageId){
if (mImage !=null) {
mImage.setImageResource(imageId);
}
}
}

注释:

1.关于isInEditMode
上面代码如果不加isInEditMode,在可视化界面会报错,无法预览我们的卡片布局。虽然编译运行后能正常显示,但不方便我们调整界面。加上isInEditMode后step3 中的布局的预览效果见下面图二,因为当前正处于编辑模式,所以部分代码被忽略,无法看到完整效果。

关于isInEditMode,官方的解释是:

Indicates whether this View is currently in edit mode. A View is usually in edit mode when displayed within a developer tool. For instance, if this View is being drawn by a visual user interface builder, this method should return true. Subclasses should check the return value of this method to provide different behaviors if their normal behavior might interfere with the host environment. For instance: the class spawns a thread in its constructor, the drawing code relies on device-specific features, etc. This method is usually checked in the drawing code of custom widgets.
来源

2.关于getDimension(),getDimensionPixelOffset(),getDimensionPixelOffset()的区别

简单粗暴的解释就是:
这三个函数返回的都是绝对尺寸,而不是相对尺寸(dp\sp等)。如果getDimension()返回结果是20.5f,那么getDimensionPixelSize()返回结果就是21,getDimensionPixelOffset()返回结果就是20。
具体可看这里和这里

《自定义组合控件实现布局重用》 图二.png

step4: 引用布局实现图一


xmlns:card="http://schemas.android.com/apk/res-auto"
android:layout_
android:layout_>
android:layout_
android:layout_
android:orientation="vertical">

android:id="@+id/topPic"
android:layout_
android:layout_
android:scaleType="centerCrop"
android:src="@drawable/image2" />

...

...

android:layout_
android:layout_
android:layout_marginBottom="16dp"
android:layout_marginTop="4dp"
android:gravity="center"
android:orientation="horizontal">
android:id="@+id/homeGuide"
android:layout_
android:layout_
android:background="#FFAA3D"
android:gravity="center"
card:card_image_
card:card_image_src="@mipmap/ic_launcher"
card:card_image_
card:card_text="Ruby"
card:card_text_margin_top="2dp"
card:card_text_size="12sp" />
android:id="@+id/classSetting"
android:layout_
android:layout_
android:layout_marginLeft="4dp"
android:background="#3398CC"
android:gravity="center"
card:card_image_
card:card_image_src="@mipmap/ic_launcher"
card:card_image_
card:card_text="Swift"
card:card_text_margin_top="2dp"
card:card_text_size="12sp" />



注释:

前面3步已经实现了一个简单的组合控件,剩下的就是使用这个自定义控件了,用法和使用系统自带的控件类似。
要注意的是这里命名空间有两种方式可选(本例中用的是第二种)

  1. xmlns:名称=”http://schemas.android.com/apk/res/包路径”
  2. xmlns:名称=”http://schemas.android.com/apk/res-auto“
    如果当前工程是作为lib使用时,使用第一种方式会出现找不到自定义属性的错误。
    以下是官方解释

Added support for custom views with custom attributes in libraries. Layouts using custom attributes must use the namespace URI http://schemas.android.com/apk/res-auto instead of the URI that includes the app package name. This URI is replaced with the app specific one at build time
来源点这里

以上就是一个自定义组合控件的完整步骤了。


推荐阅读
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • iOS超签签名服务器搭建及其优劣势
    本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • Java图形化计算器设计与实现
    本文介绍了使用Java编程语言设计和实现图形化计算器的方法。通过使用swing包和awt包中的组件,作者创建了一个具有按钮监听器和自定义界面尺寸和布局的计算器。文章还分享了在图形化界面设计中的一些心得体会。 ... [详细]
  • 今日份分享:Flutter自定义之旋转木马
    今日份分享:Flutter自定义之旋转木马-先上图,带你回到童年时光:效果分析子布局按照圆形顺序放置且平分角度子布局旋转、支持手势滑动旋转、快速滑动抬手继续旋转、自动旋转支持X轴旋 ... [详细]
author-avatar
元元木樨_669
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有