Android笔记(六十七) 自定义控件

实际编程中,系统提供的控件往往无法满足我们的需求,一来是样子丑陋,二来是一些复杂的组合需要多次使用的话,每次都写一堆控件的组合会很耗费时间,所以我们将这些组件的组合自定义为一个新的控件,以后使用的时候直接用该控件,方便又简单。最常见的例子就是软件中的titleTar

实现自定义控件的步骤:

1.设置控件的属性

2.实现我们的View

3.引用我们自定的View

  官方文档:http://developer.android.com/training/custom-views/create-view.html

下面开始:

设置控件的属性:

  分析一下上面四个titleBar,都是由一个居中的文本和一个右边一个图片按钮组成,只不过后面两个没有按钮而已

  那么我们自定义的这个组件就得包含一下几个基本属性:文本内容,文本大小,文本颜色,按钮路径

  在value中新建一个xml文件attrs.xml,把这些属性创建出来

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCustomTitleBar">
        <attr name="titleText" format="string"/>
        <attr name="titleTextSize" format="dimension"/>
        <attr name="titleTextColor" format="color"/>
        <attr name="titleButtonImage" format="reference"/>
    </declare-styleable>
</resources>
  declare-styleable标签是用来定义自定义控件的属性的,我们的控件属性都以attr形式存放在declare-styleable标签中,format是用来形容该属性的类型,有如下值可选:string,color,dimension,integer,enum,reference,float,boolean,fraction,flag

实现我们的View

定义一个继承自RelativeLayout的类MyCustomTitltBar,然后在他的构造方法中获取我们自定义的控件样式

package cn.lixyz.customviewdemo;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;

@SuppressLint("NewApi")
public class MyCustomTitleBar extends RelativeLayout {

    // 定义自定义控件包含的组件
    private TextView title;
    private ImageButton button;

    // 定义控件的属性
    private String titleText;
    private float titleTextSize;
    private int titleTextColor;
    private Drawable titleButtonImage;

    // 为每个控件定义LayoutParams
    private LayoutParams textLayoutParams;
    private LayoutParams buttonLayoutParams;

    public MyCustomTitleBar(Context context, AttributeSet attrs) {
        super(context, attrs);

        // 获取我们定义的属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyCustomTitleBar);

        titleText = array.getString(R.styleable.MyCustomTitleBar_titleText);
        titleTextColor = array.getColor(R.styleable.MyCustomTitleBar_titleTextColor, 0);
        titleTextSize = array.getDimension(R.styleable.MyCustomTitleBar_titleTextSize, 10);
        titleButtonImage = array.getDrawable(R.styleable.MyCustomTitleBar_titleButtonImage);

        // 回收,以防出错
        array.recycle();

        // 新建包含的子组件
        title = new TextView(context);
        button = new ImageButton(context);

        // 为子组件赋值
        title.setText(titleText);
        title.setTextColor(titleTextColor);
        title.setTextSize(titleTextSize);
        button.setBackground(titleButtonImage);

        // 设置背景色
        setBackgroundColor(0xFF38373c);

        // 设置包含控件的属性并添加到view中
        textLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        textLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        addView(title, textLayoutParams);
        buttonLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        buttonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        addView(button, buttonLayoutParams);
    }
}

   其中LayoutParams是用于child view(子视图) 向 parent view(父视图)传达自己的意愿的一个东西

  在获取属性的时候,android定义的格式为控件名_属性名  例如上面的MyCustomTitleBar_titleText、MyCustomTitleBar_titleTextSize

LayoutParams继承于Android.View.ViewGroup.LayoutParams. 
      LayoutParams相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息。假设在屏幕上一块区域是由一个Layout占领的,如果将一个View添加到一个Layout中,最好告诉Layout用户期望的布局方式,也就是将一个认可的layoutParams传递进去。 
      可以这样去形容LayoutParams,在象棋的棋盘上,每个棋子都占据一个位置,也就是每个棋子都有一个位置的信息,如这个棋子在4行4列,这里的“4行4列”就是棋子的LayoutParams。 
      但LayoutParams类也只是简单的描述了宽高,宽和高都可以设置成三种值: 
           1,一个确定的值; 
           2,FILL_PARENT,即填满(和父容器一样大小); 
           3,WRAP_CONTENT,即包裹住组件就好。

http://byandby.iteye.com/blog/816718

  TypedArray实例是个属性的容器,通过context.obtainStyledAttributes()方法返回得到

引用我们自定的View

在布局文件中引入我们自定义的控件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res/cn.lixyz.customviewdemo"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="cn.lixyz.customviewdemo.MainActivity" >

    <cn.lixyz.customviewdemo.MyCustomTitleBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        custom:titleButtonImage="@drawable/image"
        custom:titleText="通讯录"
        custom:titleTextColor="#ffffff"
        custom:titleTextSize="5dp" >
    </cn.lixyz.customviewdemo.MyCustomTitleBar>

    <cn.lixyz.customviewdemo.MyCustomTitleBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        custom:titleButtonImage="@drawable/plus"
        custom:titleText="微信"
        custom:titleTextColor="#ffffff"
        custom:titleTextSize="5dp" >
    </cn.lixyz.customviewdemo.MyCustomTitleBar>

    <cn.lixyz.customviewdemo.MyCustomTitleBar
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_marginTop="10dp"
        custom:titleText="发现"
        custom:titleTextColor="#ffffff"
        custom:titleTextSize="5dp" >
    </cn.lixyz.customviewdemo.MyCustomTitleBar>

    <cn.lixyz.customviewdemo.MyCustomTitleBar
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_marginTop="10dp"
        custom:titleText="我"
        custom:titleTextColor="#ffffff"
        custom:titleTextSize="5dp" >
    </cn.lixyz.customviewdemo.MyCustomTitleBar>

</LinearLayout>

一定要在布局中引入我们的命名空间

  格式为:xmlns:自定义名称="http://schemas.android.com/apk/res/包名"
  因为只有引入了我们的命名空间,才可以使用xxx:xxx格式来设置我们定义的属性,我们平时使用的android:xx也是因为上面的xmlns:android="http://schemas.android.com/apk/res/android"
  这样运行一下软件查看效果

      为按钮设置点击事件

观察我们平时为按钮设置点击事件时候的方法:

bt.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        });

我们通过按钮的setOnClickListener方法传入一个匿名内部类OnClickListener为按钮设置点击事件,我们查看OnClickListener的介绍

    /**
     * Interface definition for a callback to be invoked when a view is clicked.
     */
    public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(View v);
    }

  

我们也可以仿照这个形式,为我们的MyCustomTieleBar设置一个setCustomTitleBarListener,然后传入一个内部类来让这个按钮的点击调用这个类的click方法

修改MyCustomTitleBar:

package cn.lixyz.customviewdemo;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TextView;

@SuppressLint("NewApi")
public class MyCustomTitleBar extends RelativeLayout {

    // 定义自定义控件包含的组件
    private TextView title;
    private ImageButton button;

    // 定义控件的属性
    private String titleText;
    private float titleTextSize;
    private int titleTextColor;
    private Drawable titleButtonImage;

    // 为每个控件定义LayoutParams
    private LayoutParams textLayoutParams;
    private LayoutParams buttonLayoutParams;

    private customTitleBarListener listener;

    public interface customTitleBarListener {
        public void click();
    }

    public void setCustomTitleBarListener(customTitleBarListener listener) {
        this.listener = listener;
    }

    public MyCustomTitleBar(Context context, AttributeSet attrs) {
        super(context, attrs);

        // 获取我们定义的属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyCustomTitleBar);

        titleText = array.getString(R.styleable.MyCustomTitleBar_titleText);
        titleTextColor = array.getColor(R.styleable.MyCustomTitleBar_titleTextColor, 0);
        titleTextSize = array.getDimension(R.styleable.MyCustomTitleBar_titleTextSize, 10);
        titleButtonImage = array.getDrawable(R.styleable.MyCustomTitleBar_titleButtonImage);

        // 回收,以防出错
        array.recycle();

        // 新建包含的子组件
        title = new TextView(context);
        button = new ImageButton(context);

        // 为子组件赋值
        title.setText(titleText);
        title.setTextColor(titleTextColor);
        title.setTextSize(titleTextSize);
        button.setBackground(titleButtonImage);

        // 设置背景色
        setBackgroundColor(0xFF38373c);

        // 设置包含控件的属性并添加到view中
        textLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        textLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
        addView(title, textLayoutParams);
        buttonLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        buttonLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        addView(button, buttonLayoutParams);

        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                listener.click();
            }
        });

    }
}

  这样我们在MainActivity中就可以为按钮设置点击事件了

package cn.lixyz.customviewdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

    private MyCustomTitleBar addressListBar, wechatBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button bt = new Button(this);
        bt.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

            }
        });

        addressListBar = (MyCustomTitleBar) findViewById(R.id.addressListBar);
        wechatBar = (MyCustomTitleBar) findViewById(R.id.wechatBar);

        addressListBar.setCustomTitleBarListener(new MyCustomTitleBar.customTitleBarListener() {

            @Override
            public void click() {
                Toast.makeText(MainActivity.this, "通讯录按钮被点击", Toast.LENGTH_SHORT).show();
            }
        });
        wechatBar.setCustomTitleBarListener(new MyCustomTitleBar.customTitleBarListener() {

            @Override
            public void click() {
                Toast.makeText(MainActivity.this, "微信按钮被点击", Toast.LENGTH_SHORT).show();
            }
        });

    }

}

 

 
时间: 2024-10-09 22:51:01

Android笔记(六十七) 自定义控件的相关文章

Android笔记二十七.Service组件入门(一).什么是Service?

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.Service 1.Service简介 Service为Android四大组件之一,Service与Activity组件相似,都代表可执行的程序且有自己的生命周期,唯一的区别是Activity组件提供界面方便人机交互而Service只在后台运行且没有交互界面.Service是android 系统中的一种组件,它们都是从Context派生出来的,但是它不能自己运行,只能在后台运行,并且可以和其

Android笔记六.深入理解Intent和IntentFilter(二)

深入理解Intent和IntentFiler(二) Jiangdg_VIP http://blog.csdn.net/u012637501 在上一篇文章中,我们比较详细学习了"Intent"的相关知识,现在将学习如何设置Intent对象的这些属性以及如何使用他们来启动组件.Intent对象是一组信息,我们可以通过设置其Action.Data.Category属性来指定启动哪个组件并完成什么样的动作(包含动作所需的数据). "意图"分为显示intent和隐式inten

Android笔记二十七.Bitmap之简易图片查看器

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 为了增强用户之间的交互,Android系统中提供了一些API和部件给我们开发美观有趣的应用.比如Android系统提供了ImageView来显示静态图片.AnimationDrawble来开发逐帧动画以及通过Animation对普通图片使用不减动画等.另外,Android应用中的图片不仅包括*.png.*.jpg.*.gif等格式的位图,也包括使用XML资源文件定义的各种Drawable对象.关

Android笔记(六十二)网络框架volley

什么是Volley 很多时候,我们的APP都需要用到网络技术,使用HTTP协议来发送接收数据,谷歌推出了一个网络框架——volley,该框架适合进行数据量不大,但通信频繁的网络操作. 它的优点: (1)默认Android2.3及以上基于HttpURLConnection,2.3以下使用基于HttpClient: (2)符合Http 缓存语义 的缓存机制(提供了默认的磁盘和内存等缓存): (3)请求队列的优先级排序: (4)提供多样的取消机制: (5)提供简便的图片加载工具(其实图片的加载才是我们

Android笔记(六十八) Fragment总结

Fragment的产生: 为了适应各种尺寸的屏幕,谷歌推出Fragment,可以把Fragment成Activity的一个组成部分,它拥有自己的生命周期.可以接收并处理用户的各种事件,还可以动态的增删改某个Fragment Fragment的使用 可以把Fragment当成普通的控件使用,直接写在布局文件中,然后新建一个继承自Fragment的类加载这个布局,然后在Activity的布局文件中直接引用这个Fragment,就是这么简单: MainActivity.java package com

Android笔记(六十五) android中的动画——属性动画(propertyanimation)

补间动画只能定义起始和结束两个帧在“透明度”.“旋转”.“倾斜”.“位移”4个方面的变化,逐帧动画也只能是播放多个图片,无法满足我们日常复杂的动画需求,所以谷歌在3.0开始,推出了属性动画(property animation) 属性动画已经不再是针对View来设计的了,也不仅限定于只能实现移动.缩放.淡入淡出这几种动画操作,同时也不再是一种视觉上的动画效果了.它实际上是一种不断的对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性. ValueAnimator Val

Android笔记(六十三) android中的动画——逐帧动画( frame-by-frame animation)

就好像演电影一样,播放实现准备好的图片,来实现动画效果. 逐帧动画需要用到AnimationDrawable类,该类主要用于创建一个逐帧动画,然后我们把这个动画设置为view的背景即可. android提供两种方法为AnimationDrawable添加帧:XML定义和JAVA代码创建. XML 因为动画帧的资源需要是一个Drawable对象,所以需要把它放到Drawable目录下.在<animation-list>使用<item>来添加一帧 anima.xml <?xml

Android笔记(六十四) android中的动画——补间动画(tweened animation)

补间动画就是只需要定义动画开始和结束的位置,动画中间的变化由系统去补齐. 补间动画由一下四种方式: 1.AplhaAnimation——透明度动画效果 2.ScaleAnimation ——缩放动画效果 3.TranslateAnimation——位移动画效果 4.RotateAnimation——旋转动画效果 1.AplhaAnimation AplhaAnimation的参数: fromAlpha:动画开始时的透明度,0.0表示完全透明 toAlpha:动画结束时的透明度,1.0表示完全不透

Android笔记(六十六) android中的动画——XML文件定义属性动画

除了直接在java代码中定义动画之外,还可以使用xml文件定义动画,以便重用. 如果想要使用XML来编写动画,首先要在res目录下面新建一个animator文件夹,所有属性动画的XML文件都应该存放在这个文件夹当中.然后在XML文件中我们一共可以使用如下三种标签: <animator>  对应代码中的ValueAnimator <objectAnimator>  对应代码中的ObjectAnimator <set>  对应代码中的AnimatorSet 使用XML设置动