【安卓自定义控件系列】安卓自定义控件之组合控件

在安卓开发中,谷歌已经为我们提供了许多原生控件,基本上能够满足我们日常的开发需求,但是某些项目中原生控件可能达不到产品所要求的各式各样的酷炫效果或功能效果,这个时候我们只能自己自定义控件来满足项目需求,我们知道自定义控件包括三种方式:

1继承控件,即继承谷歌提供的原生控件,在此基础上提供一些原生控件不具备的功能,如github上各种酷炫效果的开源组件基本上都是采用的这种方式.

2组合控件:即组合多个原生控件来达到某些单个原生控件原本不具备的功能,这个在日常开发中应该是使用的比较多的,如基本上每个App都存在一个标题栏,而这些标题栏是可以被复用的,此时我们可以将其抽象出来组合为一个控件,这样在需要标题栏的地方直接使用该控件。(当然也可以采用include布局的方式,但是这样仅仅只是界面复用而已,功能不能复用)

3自绘控件:即直接继承自View类,然后自己重写onDraw方法,某些情况下可能需要重写onMeasure方法。

这三种方式,第一种方式我们使用的很少,因为github上大量优秀的开源组件就是采用的这种方式,如下拉刷新上拉加载的listView,侧滑删除的listView等,因此我们只需要直接拿来用就可以了,不要去重复造轮子,当然如果是学习自定义控件的知识的话,我们也可以直接去阅读这些开源项目的源代码,第二种方式我们使用的比较多的地方就是一个App的标题栏,通常都是采用的这种方式来完成的,第三种方式在一般的项目中很少使用到,除非项目需要完成一些复杂的效果。本博客将以第二中方式即组合控件为例来讲解安卓自定义控件的使用,将以模仿腾讯QQ的标题栏为例来教大家如何自定义组合控件。首先我们来看一下腾讯QQ的标题栏。然后按照这个样子我们自己模仿自定义一个标题栏控件。当然QQ的标题栏还是比较复杂的,因为标题栏中的文字会随着用户点击底部不同的button而显示不同的内容,当然这个功能个也很好实现,关键是如果要截图的话得截几张图,这里我就选择最具代表性的一个界面,其余的看官可以自己用QQ试一下。

可以看到在左侧是一个ImageView,中间是两个button,点击不同button显示不同内容,当然这是在消息界面,因此中间是两个button,而在联系人与动态界面中间只显示文字而已,因此此时中间是TextView,右侧基本上也是同样的道理。所以第一步我们需要在layout布局文件中组合控件来到达这样的一个界面效果。

common_title_bar的layout文件如下:

<?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"
        android:id="@+id/relativeLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#fff"
       >

    <hq.king.view.CircleImageView
        android:paddingLeft="4dp"
        android:id="@+id/title_bar_leftImg"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="7dp"
        android:background="@drawable/title_bar_image_shape"
        app:civ_border_width="1dp"
        app:civ_border_color="@color/blue"
        />

    <TextView
        android:id="@+id/center_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="14dp" />

    <Button
        android:id="@+id/title_bar_rightBtn"
        android:layout_width="35dp"
        android:layout_height="30dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="7dp"
        android:layout_marginRight="3dp"
        android:background="#fff"/>

    <LinearLayout
        android:id="@+id/title_bar_linearLayout"
        android:layout_width="150dp"
        android:layout_height="30dp"
        android:layout_centerInParent="true"
        android:layout_marginLeft="60dp"
        android:layout_toRightOf="@+id/imageView1" >

        <Button
            android:id="@+id/title_bar_linear_leftBtn"
            android:layout_width="70dp"
            android:layout_height="30dp"
            android:background="@drawable/title_bar_linear_leftbtn_shape"
             />

        <Button
            android:id="@+id/title_bar_linear_rightBtn"
            android:layout_width="70dp"
            android:layout_height="30dp"
            android:background="@drawable/title_bar_linear_rightbtn_shape"/>

    </LinearLayout>
</RelativeLayout>

可以看到该布局的根布局是一个RelativeLayout,当然这个是和具体的组合控件的界面相关的,不过像这种标题栏我们一般都使用RelativeLayout布局,然后在该布局中我们基本上按照前面的分析组合了几个原生的控件,当然那个ImageView为了达到和腾讯QQ一样的效果,我采用的是开源的CircleImageView,这些组合控件之间的位置关系通过相对布局来控制。

接下来就是自定义组合控件了,代码如下:

public class TitleBarView extends RelativeLayout {

	private Context mContext;
	Button rightBtn;
	TextView center_tv;
	LinearLayout title_linearlayout;
	Button linear_leftBtn;
	Button linear_rightBtn;
	ImageView leftImg;

	public TitleBarView(Context context) {
		super(context);
		mContext=context;
		findView();
		// TODO Auto-generated constructor stub
	}

	public TitleBarView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext=context;
		findView();
	}
	public void findView()
	{

		LayoutInflater.from(mContext).inflate(R.layout.common_title_bar, this);

		 leftImg=(ImageView) findViewById(R.id.title_bar_leftImg);
		 rightBtn=(Button)findViewById(R.id.title_bar_rightBtn);
		 center_tv=(TextView) findViewById(R.id.center_tv);
		 title_linearlayout=(LinearLayout) findViewById(R.id.title_bar_linearLayout);
		 linear_leftBtn=(Button) findViewById(R.id.title_bar_linear_leftBtn);
		 linear_rightBtn=(Button) findViewById(R.id.title_bar_linear_rightBtn);

	}
	public void setCommonTitle(int leftImg_vi,int centerLinear_vi,int textView_vi,int rightBtn_vi)
	{

		leftImg.setVisibility(leftImg_vi);
		title_linearlayout.setVisibility(centerLinear_vi);
		center_tv.setVisibility(textView_vi);
		rightBtn.setVisibility(rightBtn_vi);

	}
	public void setDefaultImgLeft(int icon){
		Drawable img=mContext.getResources().getDrawable(icon);
		leftImg.setImageDrawable(img);;
	}
	public void setUserImgLeft(Bitmap bitmap)
	{
		leftImg.setImageBitmap(bitmap);

	}
	public void setBtnRight(int icon)
	{
		rightBtn.setText(icon);

	}
	public void setBtnRightText(String str)
	{
		rightBtn.setText(str);

	}

	public void setBtnRightIcon(int icon)
	{

		Drawable img=mContext.getResources().getDrawable(icon);
		rightBtn.setBackgroundDrawable(img);

	}
	public void setBtnRightDrawable(Drawable img)
	{

		rightBtn.setBackgroundDrawable(img);

	}

	public void setTitleLeft(int resId){
		linear_leftBtn.setText(resId);
	}

	public void setTitleRight(int resId){
		linear_rightBtn.setText(resId);
	}
	public void setTitleText(int txtRes){
		center_tv.setText(txtRes);
	}

	public void setLefImgtOnclickListener(OnClickListener listener){
		leftImg.setOnClickListener(listener);
	}

	public void setBtnRightOnclickListener(OnClickListener listener){
		rightBtn.setOnClickListener(listener);
	}

	public ImageView getTitleLeft(){
		return leftImg;
	}

	public Button getTitleRight(){
		return rightBtn;
	}

}

可以看到,自定义的TitleBarView继承自RelativeLayout,因为我们前面布局文件中根布局使用的是RelativeLayout,当然也可以不这么做,但这样做规范一些,然后自定义控件TitleBarView的构造函数中使用LayoutInflater.from(mContext).inflate(R.layout.common_title_bar, this);语句将common_title_bar布局文件中的布局解析出来,当然我这里为了代码规范,在自定义控件TitleBarView的构造函数中使用的是findView()函数,然后在该函数中对控件进行初始化,这样做代码逻辑清晰。然后在该TitleBarView中提供一些

方法来控制组合控件的可见性与某些功能,因为我们知道腾讯QQ的标题栏随着底部不同button被点击标题栏中间会显示不同的控件,这我们在前面已经分析过,因此我们需要提供一个控制这些组合控件可见性的方法,除了可见性外还需提供一些功能方法,这个视具体业务需求而定,这样会具备更好的扩展性。

通过前面两个步骤,一个自定义的组合控件就已经完成了,余下的就是如何使用了,这个也很简单,在需要使用该自定义控件的布局文件中使用该自定义控件完整的路径名即可,即包名+类名,如下所示:

<com.example.view.TitleBarView
    android:id="@+id/title_bar"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    >

</com.example.view.TitleBarView>

运行之后效果如下:

这样一个高仿腾讯QQ的标题栏就做出来了,当然这个运行结果是我的高仿腾讯QQ即时IM项目的运行结果,前面的代码也是在该项目中用到的代码,该项目已开源,如果看官想体验完整的效果可以follow我的github,start与fork我的开源项目,我的githubhttps://github.com/HuTianQi

如果大家觉得不错记得小手一抖点个赞哦,欢迎大家关注我的博客账号,将会不定期为大家分享技术干货,福利多多哦!

时间: 2024-12-29 10:00:26

【安卓自定义控件系列】安卓自定义控件之组合控件的相关文章

Android自定义控件View(三)组合控件

不少人应该见过小米手机系统音量控制UI,一个圆形带动画效果的音量加减UI,效果很好看.它是怎么实现的呢?这篇博客来揭开它的神秘面纱.先上效果图 相信很多人都知道Android自定义控件的三种方式,Android自定义控件View(一)自绘控件,Android自定义控件View(二)继承控件,还有就是这一节即将学习到的组合控件.我们通过实现圆形音量UI来讲解组合控件的定义和使用. 组合控件 所谓组合控件就是有多个已有的控件组合而成一个复杂的控件.比如上图的音量控件就是一个完美的组合控件.我们来分析

Android自定义控件系列一:如何测量控件尺寸

测量控件尺寸(宽度.高度)是开发自定义控件的第一步,只有确定尺寸后才能开始画(利用canvas在画布上画,我们所使用的控件实际上都是这样画上去的).当然,这个尺寸是需要根据控件的各个部分计算出来的,比如:padding.文字大小,间距等. 非容器控件的onMeasure 下面我们就来看看如何给非容器控件(即直接extends View)这只尺寸的: 1.@Override 2.protected void onMeasure(int widthMeasureSpec, int heightMea

安卓自定义组合控件--toolbar

最近在学习安卓APP的开发,用到了toolbar这个控件, 最开始使用时include layout这种方法,不过感觉封装性不好,就又改成了自定义组合控件的方式. 使用的工具为android studio 2.2,简称AS吧 1.首先创建一个新的自定义控件,如下图.AS会创建3个文件,  一个java文件,一个layout中的xml文件(这个是布局文件),一个values中的xml文件(这个是属性文件) 2. 修改布局文件,代码如下.这里使用了RelativeLayout,  并且宽度和高度都选

Android自定义控件之自定义组合控件(三)

前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发成本,以及维护成本. 使用自定义组合控件的好处? 我们在项目开发中经常会遇见很多相似或者相同的布局,比如APP的标题栏,我们从三种方式实现标题栏来对比自定义组件带来的好处,毕竟好的东西还是以提高开发效率,降低开发成本为导向的. 1.)第一种方式:直接在每个xml布局中写相同的标题栏布局代码 <?xm

自定义组合控件和在自定义控件中使用自定义属性

今天,整理了一下我平时的笔记,写一个比较简单的自定义组合控件,仅供小白参考,大神请绕道,希望能够对大家有一些帮助 首先,得明白为什么我们需要自定义组合控件,它是因为原有控件并不能满足开发的需求,或者说并不能达到我们想要的一种效果,这个时候,就需要我们自己定义一些控件,以达到目的 ![先来看一下效果](http://img.blog.csdn.net/20160716224219109) 个人总结自定义控件的步骤: 1.先写一个布局,这里我用的是一个相对布局,我这里的相对布局就是根布局了 <?xm

【自定义控件】组合控件

组合控件是自定义控件的一种,只不过它是由其他几个原生控件组合而成,故名组合控件. 在实际项目中,GUI会遇到一些可以提取出来做成自定义控件情况. 一个自定义控件的好处就是把一些需要模块化的UI和逻辑放在一起,做到了高内聚,向其他模块提供接口并很少 依赖外界,这样就是低耦合.一个自定义控件就是一个封闭的王国,这里由你掌控. 上述是我自己的一个体会,想必大家也会常做自定义控件吧,就像逻辑部分的模块化一样. 下面我要做一个例子,请看完成图. 下面一排图片加文字就是组合控件了,我是怎么做的呢? 其实这里

Andriod 自定义控件之创建可以复用的组合控件

前面已学习了一种自定义控件的实现,是Andriod 自定义控件之音频条,还没学习的同学可以学习下,学习了的同学也要去温习下,一定要自己完全的掌握了,再继续学习,贪多嚼不烂可不是好的学习方法,我们争取学习了一种技术就会一种技术,而且不光看了就算了,最好的方法就是看完我自己再练习下,再扩展下,在原来的基础上在添加一些东西,比如,增加一些功能实现等等. 今天我们打算学习下另外一种自定义控件,就是创建可重复使用的组合控件,那么问题来了: 什么是可重复使用?就是在应用中,可以在多个地方共同使用一套代码.这

自定义控件之创建可以复用的组合控件(三)

前面已学习了两种自定义控件的实现,分别是自定义控件之对现有控件拓展(一)和 自定义控件之直接继承View创建全新视图(二),还没学习的同学可以学习下,学习了的同学也要去温习下,一定要自己完全的掌握了,再继续学习,贪多嚼不烂可不是好的学习方法,我们争取学习了一种技术就会一种技术,而且不光看了就算了,最好的方法就是看完我自己再练习下,再扩展下,在原来的基础上在添加一些东西,比如,增加一些功能实现等等. 今天我们打算学习下另外一种自定义控件,就是创建可重复使用的组合控件,那么问题来了: - 什么是可重

Android自定义控件——自定义组合控件

转载请注明出处http://blog.csdn.net/allen315410/article/details/39581055  前面几篇博文介绍了Android如何自定义控件,其实就是讲一下如何"从无到有"的自定义一个全新的控件,继承View或者继承ViewGroup,复写其相关方法,这种自定义控件的方式相对来说难度较大,而且并不是所有需要新控件的情况下,都要这样进行.有很多情况下,我们只要运用好Android给我提供好的控件,经过布局巧妙的结合在一起,就是一个新的控件,我称之为&