Android开发技巧——自定义控件之组合控件

我准备在接下来一段时间,写一系列有关Android自定义控件的博客,包括如何进行各种自定义,并分享一下我所知道的其中的技巧,注意点等。

还是那句老话,尽管我知道会被爬虫机器给过滤掉。

本文原创,转载请注明在CSDN博客上的出处:

http://blog.csdn.net/maosidiaoxian/article/details/49884261

今天写第一篇,就先写一下最简单的,也就是我们大概最早接触的一类自定义——组合控件。

这里仅讨论使用布局文件来进行组合控件。

为什么不用Java代码来写布局?原因是没有布局文件直观明了,能预览,好维护。

下面来看一个例子。

假如我们在一个界面当中的某部分布局,在另外一个界面中也会用到。



例如如上图所示,圈起来的内容,可能除了在支付界面上用到,在记录界面上也会用到,那么,你会如何处理这种情况呢?。我们先把布局实现一下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingLeft="16dp"
                android:paddingRight="16dp"
                android:background="#494949">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/login_register"
        android:text="@string/login_guide_text"
        android:textColor="@color/white"
        android:textSize="@dimen/text_28pt"/>

    <TextView
        android:id="@+id/login_register"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="@string/u_login_or_register"
        android:textColor="@color/font_span"
        android:textSize="@dimen/text_28pt"/>
</RelativeLayout>

接着:

直接复制代码

最新手的做法是,选中,复制,到另一个布局文件粘贴。然后会发现,要改一下界面的时候,要两边跟着改。直到我们学习了<include>标签之后。

使用<include>标签

于是,我们把这部分界面给抽出来,到一个新的布局文件中。然后在两个布局当中都include一下。现在如果要改这部分的界面,我们只需要改抽出来的那个文件即可,如果不涉及到所include的布局本身的属性的话。

现在看来是不是好多了?尽管只看布局代码是这样的,但是——

通常我们都不是写一个界面就这样了事了,我们还要在Java代码上,对一些控件设置一些文字,背景色,或是设置点击事件等等。而这部分的界面相同,它们的UI逻辑通常情况下也是相同的。显然,同样的代码要写两遍,作为一个有着懒惰习惯的程序员来说,当然是极极不情愿的。

自定义组合控件

于是我们定义一个类,继承自ViewGroup的子类,因为我们这里是组合一些控件,这些控件是要放在一个控件的容器里,所以不能是继承自View。我们把这个类命名为 LoginTipView,代码如下:

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * 提示去登录注册的View
 * @author Geek_Soledad
 * @since 15-5-26
 */
public class LoginTipView extends RelativeLayout implements View.OnClickListener{
    private TextView mLogin;

    public LoginTipView(Context context, AttributeSet attrs) {
        super(context, attrs);
        addView(View.inflate(context, R.layout.view_login_tip, null));
        mLogin = (TextView) findViewById(R.id.login_register);
        mLogin.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        getContext().startActivity(new Intent(getContext(), LoginActivity.class));
    }
}

看这一行代码:

        addView(View.inflate(context, R.layout.view_login_tip, null));

我们把一个布局,通过View.inflate()方法加载出来,并且通过调用addView方法,把它加到我们的LoginTipView中。

然后在我们其他使用到这部分界面的布局代码中这样引用:

    <com.parkingwang.widget.LoginTipView
        android:id="@+id/login_view"
        android:layout_width="match_parent"
        android:layout_height="42dp"
        android:layout_alignParentBottom="true"
        tools:visibility="visible"
        android:visibility="gone"/>

并且由于我们的登录的点击事件写在了LoginTipView里,所以我们甚至不需要在其他的Java代码里来设这个点击事件。

但是上面的代码还是有很大的优化余地的。最主要的是,我们的LoginTipView本身就继承自RelativeLayout,而它里面又放了一个我们从布局文件中加载的RelativeLayout,显然这部分内容可以合并。下面开始优化:

优化

首先,我们把布局代码的根元素改为`标签:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@+id/login_register"
        android:text="@string/login_guide_text"
        android:layout_alignParentLeft="true"
        android:textColor="@color/white"
        android:textSize="@dimen/text_28pt"/>

    <TextView
        android:id="@+id/login_register"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="@string/u_login_or_register"
        android:textColor="@color/font_span"
        android:textSize="@dimen/text_28pt"/>
</merge>

然后LoginTipView代码改为如下:

public class LoginTipView extends RelativeLayout implements View.OnClickListener{
    private TextView mLogin;

    public LoginTipView(Context context, AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(context).inflate(R.layout.view_login_tip, this, true);
        this.setGravity(Gravity.CENTER_VERTICAL);
        int padding = getResources().getDimensionPixelSize(R.dimen.padding_common);
        this.setPadding(padding, 0, padding, 0);
        mLogin = (TextView) findViewById(R.id.login_register);
        mLogin.setOnClickListener(this);
        this.setBackgroundResource(R.color.bg_login_tip_view);
    }

    @Override
    public void onClick(View v) {
        LoginMainActivity.showWithClosable((Activity) getContext());
    }
}

注意,我们现在加载布局的代码改为了LayoutInflater.from(context).inflate(R.layout.view_login_tip, this, true);,当然,使用View.inflate(context, R.layout.view_login_tip, this);也是一样的,后者在方法里面也是在调用前者的方法。然后,因为我们已经改为<merge>标签了,所以要把公共的属性写到我们的LoginTipView代码里(当然,你也可以不写,那你就需要在引用这个控件的布局代码里设置其对应属性)。

我们的优化过程是,使用<merge>标签,并在inflate时传入一个ViewGroup对象,使布局文件<merge>里的控件直接加载到这个ViewGroup里,减少层级。

对于这种自定义控件,其实可以说是对组合使用的控件的封装。需要注意的是,这时候你在<merge>元素本身定义的布局属性都是无效的。而这些你需要设定的属性,比如上面例子中的背景色,你可以写在你所封装的控件里,也是写在引用它的布局里。

下篇预告:

应该会讲一下onDraw(Canvas)来实现自定义吧。

Android开发技巧——自定义控件之组合控件的更多相关文章

  1. Android开发学习笔记-自定义组合控件的过程

    自定义组合控件的过程 1.自定义一个View 一般来说,继承相对布局,或者线性布局 ViewGroup:2.实现父类的构造方法.一般来说,需要在构造方法里初始化自定义的布局文件:3.根据一些需要或者需 ...

  2. Android开发学习笔记-自定义组合控件

    为了能让代码能够更多的复用,故使用组合控件.下面是我正在写的项目中用到的方法. 1.先写要组合的一些需要的控件,将其封装到一个布局xml布局文件中. <?xml version="1. ...

  3. ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl

    原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 第四章 组合控件开发CompositeControl 大家好,今天我们来实现一个自定义的控件,之前我们已经 ...

  4. ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡

    原文:ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡 CompositeControl  后篇 --事件冒泡 系列文章链接: ASP.NET ...

  5. Android开发技巧——自定义控件之自定义属性

    Android开发技巧--自定义控件之自定义属性 掌握自定义控件是很重要的,因为通过自定义控件,能够:解决UI问题,优化布局性能,简化布局代码. 上一篇讲了如何通过xml把几个控件组织起来,并继承某个 ...

  6. Android开发技巧——自定义控件之增加状态

    Android开发技巧--自定义控件之增加状态 题外话 这篇本该是上周四或上周五写的,无奈太久没写博客,前几段把我的兴头都用完了,就一拖再拖,直到今天.不想把这篇拖到下个月,所以还是先硬着头皮写了. ...

  7. Android开发技巧——自定义控件之使用style

    Android开发技巧--自定义控件之使用style 回顾 在上一篇<Android开发技巧--自定义控件之自定义属性>中,我讲到了如何定义属性以及在自定义控件中获取这些属性的值,也提到了 ...

  8. Flutter学习笔记(38)--自定义控件之组合控件

    如需转载,请注明出处:Flutter学习笔记(38)--自定义控件之组合控件 在开始之前想先写点其他的,emm...就是今天在学习到自定义控件的时候,由于自定义控件这块一直是我的短板,无论是Andro ...

  9. 自定义控件之--组合控件(titlebar)

    自定义控件相关知识从郭霖等大神身上学习,这里只不过加上自己的理解和实践,绝非抄袭.   组合控件是自定义控件中最简单的方式,但是是入门自定义控件和进阶的过程: 那么常见的组合控件有那些? 比如titl ...

随机推荐

  1. Scala actor的使用

    Actor 为什么需要Actor? Actor的本质即万物皆Actor, Actor之间只有发送消息这一种通信方式.例如,无论是管理员让工作者干活,还是工作者把成果交还给管理员,它们之间也要通过发送消 ...

  2. not in 前面/后面存在null值时的处理

    表声明 order_header表中有ship_method列: ship_method_map表中ship_method为主键列. 需求 找出order_header表中所有ship_method不 ...

  3. PyCharm 开发Django ,错误汇总

    近期略微接触了一下Django.在学习的过程中可谓是坎坎坷坷,遇到了很多的问题. 下面就来谈一谈我对Django的一点点的见解. Django项目的创建 使用PyCharm来开发Django项目是非常 ...

  4. 对 jiffies 溢出、回绕及 time_after 宏的理解

    原文如下: 关于jiffies变量:     全局变量jiffies用来记录自启动以来产生的节拍的总数.系统启动时会将该变量初始化为0,此后,每当时钟中断产生时就会增加该变量的值.jiffies和另外 ...

  5. Android:Field can be converted to a local varible.

    背景 使用 Android Studio 开发 Android 有一段时间了,偶尔会碰到 AS 在一些私有变量上有黄色高亮提示Field can be converted to a local var ...

  6. UNIX网络编程——心跳包

    所谓的心跳包就是在客户端和服务器端间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包. 一般是用来判断对方(设备,进程或其它网元)是否正常动行,一般采用定 ...

  7. 精通CSS+DIV网页样式与布局--滤镜的使用

    在上篇博客中,小编主要简单的介绍了使用CSS,如何制作实用菜单,今天我们继续来总结有关CSS的基础知识,今天小编主要简单的来介绍一下CSS中关于滤镜的使用,首先,小编先来简单的介绍一下滤镜,我们这次来 ...

  8. JAVA之旅(二十一)——泛型的概述以及使用,泛型类,泛型方法,静态泛型方法,泛型接口,泛型限定,通配符

    JAVA之旅(二十一)--泛型的概述以及使用,泛型类,泛型方法,静态泛型方法,泛型接口,泛型限定,通配符 不知不觉JAVA之旅已经写到21篇了,不得不感叹当初自己坚持要重学一遍JAVA的信念,中途也算 ...

  9. Mysql中limit的用法详解

    Mysql中limit的用法详解 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,为我们提供了limit这样一个功能. SELECT * FROM table LIMIT [offset ...

  10. 【翻译】Sencha Cmd中脚本压缩方法之比较

    概述 为什么要修改默认设置 YUI压缩 Google Closure编译器 UglifyJS 案例研究Ext JS 6示例应用程序 注意事项 自定义JS压缩 小结 概述 这么多年来,Web开发人员都被 ...