自定义View

 一.前言

         安卓提供了许多易用的,功能强大的View对象,如TextView,ImageView等等。但是这些View不一定能满足我们的需要,我们需要自定义View。下面我们以两部分来说明,包括自定义View和自定义属性。下面我们来看下

       1.关于Activity,View和布局文件的说明

              首先我们在编写安卓程序常常碰到的的三个文件,两个Java文件和一个XML文件,下面我一张图来说明

              

           其中一个布局文件对应一个View控件,当然我们也可以在一个布局文件中放别的View控件,但是这个View控件也是对应一个布局的,(这么说可能有问题,如果有错可以指正)。当我们创建View作为一个容器来包装View,然后我们在Activity中获取这些View对象,通过获取View中的值来进行逻辑判断,从而去设置View的值来完成你的业务逻辑。好的接下来让我们创建自定义View.

二.自定义View

       1.创建一个布局文件

                这个布局标识这个View的样式,这样我们就能把View的样子勾勒出来。下面我们就让我们创建一个RelativeLayout布局文件来定义我们的样式。

               

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:padding="10dp"
        xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:textColor="#000"
            android:textSize="22sp"


    />

    <TextView
            android:id="@+id/tv_desc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/tv_title"
            android:paddingTop="5dp"
            android:text=""
            android:textColor="#a000"


    />
    <CheckBox
            android:id="@+id/cb_status"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentTop="true"
            android:layout_alignParentEnd="true"
            android:focusable="false"
            android:clickable="false"
            android:focusableInTouchMode="false"

    />

    <View
            android:layout_width="match_parent"
            android:layout_height="0.2dp"
            android:background="#a000"
            android:layout_alignParentBottom="true"
    />
</RelativeLayout>

  在这个布局文件中有两个TextView和一个CheckBox,以及一个View表示一条线 ,其中CheckBox中的android:focusable="false"
  ,android:clickable="false", android:focusableInTouchMode="false"表示屏蔽CheckBox的点击事件,这样就可以不用处理CheckBox的点击事件了。TextView中的text值为空,因为我们会用自定义属性来代替,这个布局的样式就是我们这个自定义View的样式了。

2.创建自定义View

     接下来我们需要一个容器来承装这个布局文件,如下

      

@TargetApi(21)
public class SettingItemView extends RelativeLayout{
    private final static String NAMESPACE="http://schemas.android.com/apk/res-auto";
    private  TextView tv_title;
    private  TextView tv_desc;
    private CheckBox checkBox;
    private String title;
    private String desc_Off;
    private String desc_On;
    public SettingItemView(Context context) {
        super(context);
        initView();
    }

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

       title = attrs.getAttributeValue(NAMESPACE, "title");
         desc_Off = attrs.getAttributeValue(NAMESPACE, "desc_Off");
        desc_On = attrs.getAttributeValue(NAMESPACE, "desc_On");
        //System.out.println("title:"+title);
        initView();
    }

    public SettingItemView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    public SettingItemView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

        super(context, attrs, defStyleAttr, defStyleRes);
        initView();
    }

    /**
     * 初始化布局
     */
    private void initView(){
        //将自定义好的布局文件设置给当前的SettingItemView
        View setting_item = View.inflate(getContext(), R.layout.view_setting_item,this);
        checkBox  = setting_item.findViewById(R.id.cb_status);
        tv_title = setting_item.findViewById(R.id.tv_title);
        tv_desc = setting_item.findViewById(R.id.tv_desc);
        setTv_title(title);


    }

    public void setTv_title(String title){
     tv_title.setText(title);
    }

    public void setTv_desc(String desc){
        tv_desc.setText(desc);
    }

    public boolean isChecked() {
        return checkBox.isChecked();
    }

    public void setIsChecked(boolean flag) {
        this.checkBox.setChecked(flag);
        //设置状态文本描述
        if(flag){
            setTv_desc(desc_On);
        }else{
            setTv_desc(desc_Off);
        }
    }


}

   我们的View就是一个Java的Class文件,他继承了RelativeLayout这个Class,是的RelativeLayout就是安卓自己的View,用来承装他自己的布局文件,好的,现在我们要自定义View。就需要更改这个RelativeLayout,那就是新建一个类来继承他,从而改写安卓自定义的View,看看我们干了什么?首先我们在initView中来将我们自定义的布局和自定义的View关联起来,看这个代码 View setting_item = View.inflate(getContext(), R.layout.view_setting_item,this);就是我刚刚说的关联起来,然后我们可以在setting_item 获取之前在布局文件中定义的一些安卓的view对象,我们在所有构造函数都初始化了这个View,所以我们可以保证View可以被加载,同时,我们定义了一些set方法来给这些view对象设置内容,这样我们的自定义View好了,现在我们想在别的布局中使用这个View,怎么用能?如下:

  

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:itheima="http://schemas.android.com/apk/res-auto"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context="itcast.com.itcastsafe.activity.SettingActivity"
                 android:orientation="vertical"
>

    <TextView
            style="@style/TitleStyle"
            android:text="设置中心"
            android:id="@+id/textView"/>

    <itcast.com.itcastsafe.activity.view.SettingItemView
            android:id="@+id/sv_update"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            itheima:title="自动更新设置"
            itheima:desc_Off="自动更新设置已经关闭"
            itheima:desc_On="自动更新设置已经开启"
    />

</LinearLayout>

  我们新建一个布局文件,使用自定义布局需要使用自定义View的全类名,好的这样就是使用了,这里我们看到xmlns:itheima="http://schemas.android.com/apk/res-auto这个命名空间和itheima:title="自动更新设置"这个属性,这是做什么能?这个就是下来我们要说的自定义属性

 二.自定义属性

      1.创建自定义属性文件

             我们在values文件夹中创建自定义资源文件attrs.xml,内容如下:

             

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SettingItemView">
        <attr name="title" format="string"></attr>
        <attr name="desc_On" format="string"></attr>
        <attr name="desc_Off" format="string"></attr>
    </declare-styleable>
</resources>

 我们定义了一个样式,名字叫做SettingItemView,里面包含三个属性分别是title,desc_On,desc_Off,好的,下一步,我们来定位这个资源文件

2.命名空间和自定义属性使用

 我们定义资源文件,但是如何使用这个资源文件?,看之前我们的布局文件中有个xmlns:itheima="http://schemas.android.com/apk/res-auto"这个东西,早期的在安卓中需要你手动指定包名,现在在idea中,使用res-auto就能自动指定包名了,好的这样就能使用自定义属性了。itheima:title="自动更新设置",itheima:desc_Off="自动更新设置已经关闭",itheima:desc_On="自动更新设置已经开启" 这些就是自定义属性的使用方法,下面我们看如何在Activity中使用这些自定义的View。

 三.在Activity中使用自定义View

   使用自定义View和使用普通的View其实都差不多,因为自定义View就是修改了原本安卓的View。好了,看下代码吧

   

protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_setting);
        final SettingItemView settingItemView = findViewById(R.id.sv_update);
        sharedPreferences = getSharedPreferences("config",MODE_PRIVATE);
       // settingItemView.setTv_title("自动更新设置");
        if(sharedPreferences.getBoolean("auto_update",true)){

          //  settingItemView.setTv_desc("自动更新设置已经开启");
            settingItemView.setIsChecked(true);
        }else{

            //settingItemView.setTv_desc("自动更新设置已经关闭");
            settingItemView.setIsChecked(false);
        }

        settingItemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                   //判断是否选中
                   if(settingItemView.isChecked()){
                        settingItemView.setIsChecked(false);
                        //settingItemView.setTv_desc("自动更新设置已经关闭");
                        sharedPreferences.edit().putBoolean("auto_update",false).commit();
                   }else{
                       settingItemView.setIsChecked(true);
                       //settingItemView.setTv_desc("自动更新设置已经开启");
                       sharedPreferences.edit().putBoolean("auto_update",true).commit();
                   }
            }
        });


    }

 一样的使用findViewById来通过id来加载自定义的View,然后通过View中的方法来设置值,其实你注意到了吗,我们把通过View的set方法来给自定义VIew中的View来赋值,因为我们已经把这些View组成一个自定义的View了,我们不可以通过绕过自定义View来跟这些View赋值,这也告诉我们自定义View的一些场景的运用。

   四.总结

           如果你需要一个布局,而且这个布局在别的地方也要被使用,且这个布局颇为麻烦,为了解决这个问题,你可以使用自定义View来包裹这些简单View,让他成为一个整体,这样在下次使用该布局时,就不用那么麻烦的创建了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值