美文网首页
自定义组合View

自定义组合View

作者: 犀利的小眼神 | 来源:发表于2018-07-20 22:31 被阅读12次

    自定义组合控件就是将常用的组合控件效果进行封装。

    经常使用的界面,并且界面是由多个子控件或子布局组成,这时候需要组合控件
    组合控件的作用:用于封装常用的控件组合效果,方便开发者使用。

    今天的效果图如下:


    效果图

    自定义属性

    编码中会用到自定义属性,我们先来说一下自定义属性的流程。
    我们常用的官方控件,如TextView,ImageView等,常用到layout_width,layout_height等属性,都是官方帮我们自定义好的属性,所以我们可以直接拿来使用。在工作中,有些官方提供的属性不满足我们的需求,我们就需要自定义属性了。

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
    

    自定义属性的步骤:
    1.在value目录下attr.xml中声名属性的名称和类型格式。如果value目录下没有attr文件,自己创建即可。

    <resources>
        <declare-styleable name="MyToggleView">
            <!-- 显示不同的title内容,这里的属性名可随意定义,但最好不要定义和现有属性一致的名称 -->
            <attr name="item_title" format="string" />
        </declare-styleable>
    </resources>
    

    建好文件后,会自带<resources>标签,我们自己加入<declare-styleable>标签,标签内部加入name属性,此name属性是为了标识为哪个自定义View设置的属性。我们会将此自定义View的所有自定义属性都放在这个标签下。
    我们在<declare-styleable>标签下加入<attr>标签,会自动提示加入name和format属性。这个name属性即自定义属性的名字,format为自定义属性的值的类型。
    如下图所示,红框中为所有待选的属性类型。
    dimension为单位为dp或sp的值,如我们常用的宽高值。

    自定义属性的类型

    2.在activity_main.xml文件中定义名称空间和声明属性
    加入名称空间可以使用appNs属性,会帮我们自动匹配

     <LinearLayout
        android:id="@+id/activity_main"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        ...
        >
    
        <com.itheima.groupviewdemo.MyToggleView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:item_title="我的设置1">
        </com.itheima.groupviewdemo.MyToggleView>
    </LinearLayout>
    

    3.在自定义组合控件内部获取自定义属性的值,并设置到内部的控件上,此处为TextView上。

    public MyToggleView(Context context, AttributeSet set) {
       super(context, set);
    
       // 将布局和view绑定
       View view = View.inflate(context, R.layout.view_setting_item, this);
       //获取控件
       TextView tv_title = (TextView) findViewById(R.id.view_tv_title);
       // 读取自定义的属性
       TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyToggleView);
       //获取自定义属性的值
       String title = typedArray.getString(R.styleable.SettingItemView_item_title);
       //获取完成后一定要做回收处理
       ta.recycle();
       
       tv_title.setText(title_type);//设置文本
       ...
    }
    

    经过以上三个步骤,自定义属性就完成了。再复杂的自定义属性,也都是经过这三个步骤。
    若想要控制自定义控件的背景,也可以定义一个枚举类型的属性值,获取属性值并设置到控件上
    enum:枚举,表示item_background只允许输入三个(first,middle,last),分别对应int值0,1,2
    1.编写attr属性

    <declare-styleable name="MyToggleView">
    <!-- 背景的设置 -->
        <attr name="item_background">
            <enum name="first" value="0" />
            <enum name="middle" value="1" />
            <enum name="last" value="2" />
        </attr>
    ...
    <declare-styleable>
    

    2.activity_main.xml文件中引用

    <com.itheima.groupviewdemo.MyToggleView
        ...
        app:item_background="first"
    ...
    >
    </com.itheima.groupviewdemo.MyToggleView>
    

    3.在自定义组合控件中获取值,并给控制赋值

    public MyToggleView(Context context, AttributeSet set) {
       super(context, set);
       ...
          int background_type = typedArray.getInt(R.styleable.MyToggleView_item_backgroud, 0);
       ...
         int bg;
         switch (background_type) {
                case 1:
                    bg = R.drawable.seting_middle_selector;
                    break;
                case 2:
                    bg = R.drawable.seting_last_selector;
                    break;
                default:
                    bg = R.drawable.seting_first_selector;
            }
            view.setBackgroundResource(bg);//设置背景
      ...
    }
    

    我们把开关状态也设置在自定义属性中,方便在布局文件中设置一个默认开关状态。
    1.编写attr属性

        <declare-styleable name="MyToggleView">
            <attr name="toggle_on" format="boolean">
            </attr>
        </declare-styleable>
    

    2.布局文件中引用

    <com.otitan.dynamicview.view.MyToggleView
            ...
            app:toggle_on="false"
            ...
            >
        </com.otitan.dynamicview.view.MyToggleView>
    

    3.在自定义组合控件中获取值,并给控制赋值

      public MyToggleView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            view = View.inflate(context, R.layout.view_setting_item, this);
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyToggleView);//通过属性名称获取属性集合
           
            boolean isToggleOn_type = typedArray.getBoolean(R.styleable.MyToggleView_toggle_on, false);//获取开关状态
            
            iv_toggle = (ImageView) findViewById(R.id.view_iv_toggle);//开关
    
            typedArray.recycle();//释放资源
    
            isToggleOn(isToggleOn_type);
        }
    
        private boolean isToggleOn = false;
    
        public void toggle() {//对外开放一个方法,用于切换开关
            isToggleOn(!isToggleOn);
        }
        //用于内部设置开关状态
        private void isToggleOn(boolean isToggleOn) {
    
            // iv_toggle.setImageResource(isToggleOn ? R.drawable.on : R.drawable.off);
            if (isToggleOn) {
                iv_toggle.setImageResource(R.drawable.on);
                if (listener != null) {
                    listener.onToggleOpen();
                }
            } else {
                iv_toggle.setImageResource(R.drawable.off);
                if (listener != null) {
                    listener.onToggleClose();
                }
            }
            this.isToggleOn = isToggleOn;
        }
    
        //开关改变监听
        public interface OnToggleChangeListener {
            void onToggleOpen();//开关打开
    
            void onToggleClose();//开关关闭
        }
    
        private OnToggleChangeListener listener;
        public void setOnToggleChangeListener(OnToggleChangeListener listener) {
            this.listener = listener;
        }
    

    主界面控制按钮状态:

        toggle1 = (MyToggleView) findViewById(R.id.toggle1);
            toggle1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    toggle1.toggle();//切换开关状态
                }
            });
    
            toggle1.setOnToggleChangeListener(new MyToggleView.OnToggleChangeListener() {
                @Override
                public void onToggleOpen() {
                    Toast.makeText(getApplicationContext(),"开关已打开。",Toast.LENGTH_SHORT).show();
                }
    
                @Override
                public void onToggleClose() {
    
                    Toast.makeText(getApplicationContext(),"开关已关闭。",Toast.LENGTH_SHORT).show();
                }
            });
    

    自定义属性写完,基本代码也就写完了,剩下的就是在布局文件中使用自定义的组合控件了。
    在布局文件中多使用几次自定义好的组合控件,就可以完成文章开始那张图的效果。

    下面贴出完整代码:

    布局文件activity_main.xml文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.otitan.dynamicview.MainActivity">
    
        <com.otitan.dynamicview.view.MyToggleView
            android:id="@+id/toggle1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:toggle_on="false"
            app:item_backgroud="first"
            app:item_title="是否使用移动网络"
            >
        </com.otitan.dynamicview.view.MyToggleView>
    
        <com.otitan.dynamicview.view.MyToggleView
            android:id="@+id/toggle2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:toggle_on="true"
            app:item_backgroud="middle"
            app:item_title="是否使用wifi"
            >
        </com.otitan.dynamicview.view.MyToggleView>
    
        <com.otitan.dynamicview.view.MyToggleView
            android:id="@+id/toggle3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:toggle_on="false"
            app:item_backgroud="bottom"
            app:item_title="是否使用GPS"
            >
        </com.otitan.dynamicview.view.MyToggleView>
    
        <com.otitan.dynamicview.view.MyToggleView
            android:id="@+id/toggle4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:toggle_on="true"
            app:item_backgroud="first"
            app:item_title="是否打开开发者模式"
            >
        </com.otitan.dynamicview.view.MyToggleView>
    
        <com.otitan.dynamicview.view.MyToggleView
            android:id="@+id/toggle5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:toggle_on="false"
            app:item_backgroud="bottom"
            app:item_title="是否开启USB调试"
            >
        </com.otitan.dynamicview.view.MyToggleView>
    </LinearLayout>
    
    

    单个条目的布局文件view_setting_item.xml文件:

    <?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:paddingBottom="8dp"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:paddingTop="8dp" >
    
        <TextView
            android:id="@+id/view_tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:text="自动更新"
            android:textSize="18sp" />
    
        <ImageView
            android:id="@+id/view_iv_toggle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:src="@drawable/on" />
    
    </RelativeLayout>
    

    attr.xml文件:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="MyToggleView">
    
            <attr name="item_backgroud" format="enum">
                <enum name="first" value="0"></enum>
                <enum name="middle" value="1"></enum>
                <enum name="bottom" value="2"></enum>
            </attr>
    
            <attr name="item_title" format="string">
            </attr>
            <attr name="toggle_on" format="boolean">
            </attr>
    
        </declare-styleable>
    </resources>
    

    自定义组合控件:

    public class MyToggleView extends RelativeLayout {
    
        private View view;
        private ImageView iv_toggle;
    
        public MyToggleView(Context context) {
            this(context, null);
        }
    
        public MyToggleView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public MyToggleView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
    
            view = View.inflate(context, R.layout.view_setting_item, this);
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyToggleView);//通过属性名称获取属性集合
            int background_type = typedArray.getInt(R.styleable.MyToggleView_item_backgroud, 0);//获取背景值
            String title_type = typedArray.getString(R.styleable.MyToggleView_item_title);//获取文本值
            boolean isToggleOn_type = typedArray.getBoolean(R.styleable.MyToggleView_toggle_on, false);//获取开关状态
            int bg;
            switch (background_type) {
                case 1:
                    bg = R.drawable.seting_middle_selector;
                    break;
                case 2:
                    bg = R.drawable.seting_last_selector;
                    break;
                default:
                    bg = R.drawable.seting_first_selector;
            }
            view.setBackgroundResource(bg);//设置背景
            TextView tv_title = (TextView) findViewById(R.id.view_tv_title);//文本
            tv_title.setText(title_type);//设置文本
            iv_toggle = (ImageView) findViewById(R.id.view_iv_toggle);//开关
    
            typedArray.recycle();//释放资源
    
            isToggleOn(isToggleOn_type);
        }
    
        private boolean isToggleOn = false;
    
        public void toggle() {
            isToggleOn(!isToggleOn);
        }
    
        private void isToggleOn(boolean isToggleOn) {
    
    //        iv_toggle.setImageResource(isToggleOn ? R.drawable.on : R.drawable.off);
            if (isToggleOn) {
                iv_toggle.setImageResource(R.drawable.on);
                if (listener != null) {
                    listener.onToggleOpen();
                }
            } else {
                iv_toggle.setImageResource(R.drawable.off);
                if (listener != null) {
                    listener.onToggleClose();
                }
            }
            this.isToggleOn = isToggleOn;
        }
    
        public interface OnToggleChangeListener {
            void onToggleOpen();
    
            void onToggleClose();
        }
    
        private OnToggleChangeListener listener;
    
        public void setOnToggleChangeListener(OnToggleChangeListener listener) {
            this.listener = listener;
        }
    
    }
    

    最后MainActivity.java:

    public class MainActivity extends AppCompatActivity {
    
        private MyToggleView toggle1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            toggle1 = (MyToggleView) findViewById(R.id.toggle1);
            toggle1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    toggle1.toggle();
                }
            });
    
            toggle1.setOnToggleChangeListener(new MyToggleView.OnToggleChangeListener() {
                @Override
                public void onToggleOpen() {
                    Toast.makeText(getApplicationContext(),"开关已打开。",Toast.LENGTH_SHORT).show();
                }
    
                @Override
                public void onToggleClose() {
    
                    Toast.makeText(getApplicationContext(),"开关已关闭。",Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    

    相关文章

      网友评论

          本文标题:自定义组合View

          本文链接:https://www.haomeiwen.com/subject/xttcmftx.html