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


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

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


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




本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。

Android多点触摸交互处理 - 2016-07-25 17:07:15

安卓手机中,多点触摸是是最基本的操作,下面就使用程序进行演示多点触摸操作 一、获取触摸事件中的点击,移动和抬起事件,创建新的安卓项目,如下面代码所示,分别为MainActivity类代码和Layout布局文件,用于实现获取点击事件 1.1、MainActivity类中代码,代码中为布局对象root添加监听事件,使用switch进行对屏幕时间进行判断,用于判断事件的按下还是移动,在代码中      root=(RelativeLayout) findViewById(R.id.content);用于绑定布局
内容是博主照着书敲出来的,博主码字挺辛苦的,转载请注明出处,后序内容陆续会码出。 前言:ListView——列表,它作为一个非常重要的显示方式,不管是在Web中还是移动平台中,都是一个非常好的、不开或缺的展示信息的工具。在Android中,ListView控件接管了这一重担,在大量的场合下,我们都需要使用这个控件。虽然在Android 5.X时代,RecyclerView在很多地方都在逐渐取代ListView,但ListView的使用范围依然非常的广泛,它这万年老大哥的地位也不是轻易就能撼动的。下面就介绍
Android ListView使用简介 ListView 是 Android 软件开发中十分常用也十分重要的一个 UI 控件。 ListView 的每一个子项可以是一个简单的字符串,也可以是一组 View 的组合,开发者完全可以根据自己的需求来定义显示的形式。 如何使用一个 ListView 实现对数据的显示呢 ? 1. 创建 ListView 控件,已备数据显示 2. 准备要显示的数据 3. 为 ListView 构建一个数据适配器 (Adapter) 4. 绑定适配器 5. 处理 ListView
转载请标明出处: 一片枫叶的专栏 文本我们将讲解android studio打包apk,aar,jar包的相关知识。apk包就是android系统的安装包,这里没什么好说的,aar包是android中独有的类库包,而jar包是java中特有的类库包,在具体的介绍打包之前,我们先来aar包和jar包的区别。 jar包与aar包的区别 jar是java字节码文件(class文件)的归档文件,其不包含android中的资源文件等信息; aar是android中特有的归档文件,既包含字节码文件也包含android
欢迎转载,转载请注明出处: http://blog.csdn.net/dmk877/article/details/51980734 在上一篇文章中,我们详细讨论了Tween动画的xml的实现以及interpolator的使用,相信通过上篇文章大家对Tween动画的xml属性的配置会有一个详细的理解,当然这篇文章也是承接上篇文章,所以强烈建议先阅读上篇文章: Android开发之Tween(补间动画)完全解析(上) ,这篇文章将从代码的角度实现上篇文章的效果。 如有疑问请留言,如有谬误欢迎批评指正。 Tw

Android闹钟设置的解决方案 - 2016-07-25 14:07:00

Android设置闹钟并不像IOS那样这么简单,做过Android设置闹钟的开发者都知道里面的坑有多深。下面记录一下,我解决Android闹钟设置的解决方案。 主要问题 API19开始AlarmManager的机制修改。 应用程序被Kill掉后,设置的闹钟不响。 6.0以上进入Doze模式会使JobScheduler停止工作。 手机设置重启后,闹钟失效问题。 API19以上AlarmManager机制的修改 API19之前AlarmManager提供了三个设置闹钟的方法,由于业务需求闹钟只需要一次性,所以
start_kernel之前的汇编代码建立了内核临时页表,完成了内核区域的静态线性映射,保证内核可以在舒适的虚拟地址空间(运行地址和链接地址一致)运行。进入start_kernel之后就要准备建立完整的页表映射,这部分工作是在paging_init中完成。 不过在建立完整页表映射之前还需要进行一些准备工作,本文来分析下。 为了简化整个代码流程,便于分析,我的设备内核配置为不使用高端内存,不配置CONFIG_HIGHMEM。bootargs中传给内核的mem=256. 内核版本号:3.4.55 paging

App的打磨之路(下) - 2016-07-25 14:07:48

前言:该文接上两篇博文 App的打磨之路(上) 和 App的打磨之路(中) ,继续描述打包、反编译及加固。 一、打包 每个Android应用在完成后都需要打成APK包,对于单个打包的方式在此就不赘述了,基本IDE都带,只是在对外发布的应用需要配置属于该应用的唯一签名,下文主要讲述需要上传多个市场的情况下怎么批量打包。 1、Maven打包 Maven是一个项目管理工具,它包含了一个项目对象模型(Project Object Model),一组标准集合,一个项目生命周期(ProjectLifecycle),一

PendingIntent的内部机制 - 2016-07-25 14:07:48

摘自;http://my.oschina.net/youranhongcha/blog/196933   1 概述         在Android中,我们常常使用PendingIntent来表达一种“留待日后处理”的意思。从这个角度来说,PendingIntent可以被理解为一种特殊的异步处理机制。不过,单就命名而言,PendingIntent其实具有一定误导性,因为它既不继承于Intent,也不包含Intent,它的核心可以粗略地汇总成四个字——“异步激发”。         很明显,这种异步激发常常
Android framework提供了许多标准的工具,来创建有吸引力的、功能丰富的用户图形界面。但是,如果你想要更多的控制权,比如在应用程序的屏幕上绘图,或者冒险进入三维图形,你需要使用不同的工具。通过Android framework提供的OpenGL ES的API提供了一套显示高端的工具,动画图像超出你的想象,许多Android设备的图像处理单元得到了加速(GPUs)。 这节课主要开发一个OpenGL应用程序、包括设置、画对象、移动对象元素、响应触摸输入事件。 这节课的示例代码使用的是OpenGL