天天看点

Android控件与布局——基础控件CheckedTextView

        最近在用原生的控件和布局绘制一些界面并使用,虽然这些都是Android基本知识,但是有的时候真的感觉力不从心,感觉有必要对Android常用的控件和布局做一个系统的了解。后续一个月甚至更多的时间都会围绕这个主题展开,毕竟这里面还是有不少高级控件的,我也会尽量结合应用深入的进行了解。

项目GitHub地址入口

上一篇:RadioButton     下一篇:Spinner

今天,我们的主题是CheckedTextView,它是一种对TextView进行了扩展的控件,下面看一下官方文档的介绍:

* An extension to {@link TextView} that supports the {@link Checkable}
* interface and displays.
* <p>
* This is useful when used in a {@link android.widget.ListView ListView} where
* the {@link android.widget.ListView#setChoiceMode(int) setChoiceMode} has
* been set to something other than
* {@link android.widget.ListView#CHOICE_MODE_NONE CHOICE_MODE_NONE}.
           

可见,其通常配合ListView实现单选或者多选的操作,后面我们会结合ListView进行简单的演示。上面说到,这是一个继承至TextView且实现了Checkable接口的控件,下面看看其基本的使用和展示:

<CheckedTextView
        android:id="@+id/checked_textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="CheckedTextView"
        android:textSize="25sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
           
Android控件与布局——基础控件CheckedTextView

和一个TextView没有任何区别,下面,我们给上面的控件添加一个属性android:checkMark:

<CheckedTextView
        android:id="@+id/checked_textView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="CheckedTextView"
        android:textSize="25sp" />

    <CheckedTextView
        android:id="@+id/checked_textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checkMark="@drawable/checked_text_view_back"
        android:text="CheckedTextView"
        android:textSize="25sp"
        />

    <CheckedTextView
        android:id="@+id/checked_textView3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:checkMark="@drawable/checked_text_view_back"
        android:checked="true"
        android:text="CheckedTextView"
        android:textSize="25sp" />
           
Android控件与布局——基础控件CheckedTextView

可见,通过这个属性可以为CheckedTextView添加一个图标,至于TextView的设置文本相关的属性这里就不在演示了。此外,我们看到这个控件像是一个TextView与一个ImageView的组合,很像一个简单ListView的Item布局,当然这不是上面文档说其适合配合ListView的原因,之所以说其常常配合ListView使用是因为其实现了Checkable接口且ListView中有setItemCheck()这样的接口。下面是setItemCheck()的描述:

/**
 * Sets the checked state of the specified position. The is only valid if
 * the choice mode has been set to {@link #CHOICE_MODE_SINGLE} or
 * {@link #CHOICE_MODE_MULTIPLE}.
 *
 * @param position The item whose checked state is to be checked
 * @param value The new checked state for the item
 */
           

设置ListView对应position上的item的状态为checked,且只有在ListView设置为CHOICE_MODE_SINGLE和CHOICE_MODE_MULTIPLE下有效,这里这两个常参表示单选或者多选的意思。所以这也是常常使用ListView配合CheckedTextView实现单选或者多选的原因,此外,我们也可以通过上文关于RadioButton介绍中说的,使用RadioButtom配合RadioGroup实现,但是,后者只能针对定长的选项可以,对于选项数量可变的不好实现,而前者恰恰弥补了这一点。

下面就来通过ListView配合CheckedTextView实现一下多选的效果(不是通过上述方式),示例的运行结果如下:

Android控件与布局——基础控件CheckedTextView

主要的逻辑代码有我们的适配器MyAdaptor.java代码:

package aoto.com.commonwidgetandlayout.basic_widget.checkedTextView;

import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
import java.util.ArrayList;

import java.util.List;

import aoto.com.commonwidgetandlayout.R;

/**
 * author:why
 * created on: 2019/5/14 10:49
 * description:
 */
public class MyAdaptor extends ArrayAdapter<String> {
    private static final String TAG = "MyAdaptorWhy";
    private int resourceID;
    private Context context;
    private ArrayList<String> resultList;
    public MyAdaptor(@NonNull Context context, int resource, List<String> list) {
        super(context, resource,list);
        this.context = context;
        this.resourceID = resource;
        resultList=new ArrayList();
    }

    @NonNull
    @Override
    public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {

        View view;
        final ViewHolder holder;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceID, parent, false);
            holder=new ViewHolder();
            holder.checkedTextView=view.findViewById(R.id.checked_textView);
            view.setTag(holder);
        } else {
            //布局缓存处理
            view = convertView;
            holder = (ViewHolder) view.getTag();
        }

        String str = getItem(position);
        holder.checkedTextView.setText(str);
        holder.checkedTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                holder.checkedTextView.toggle();//切换选中与非选中状态
                if(holder.checkedTextView.isChecked()){
                    resultList.add(holder.checkedTextView.getText().toString());
                }
                else {
                    if(resultList.contains(holder.checkedTextView.getText().toString())){
                        resultList.remove(holder.checkedTextView.getText().toString());
                    }
                }
            }
        });
        return view;
    }

    class ViewHolder {
       CheckedTextView checkedTextView;
    }


    public ArrayList<String> getList(){
        return resultList;
    }
}
           

控制层代码CTextViewActivity.java代码:

package aoto.com.commonwidgetandlayout.basic_widget.checkedTextView;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.CheckedTextView;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;

import aoto.com.commonwidgetandlayout.R;

/**
 * @author why
 * @date 2019-5-14 10:07:30
 */
public class CTextViewActivity extends AppCompatActivity {

    private static final String TAG = "CTextViewActivityWhy";
    CheckedTextView textView;
    ListView listView;
    TextView chooseResult;
    MyAdaptor adaptor;
    ArrayList<String> nameList=new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ctext_view);
        chooseResult=findViewById(R.id.choose_result);
        listView=findViewById(R.id.name_list_view);
        nameList.add("苹果");
        nameList.add("香蕉");
        nameList.add("菠萝");
        nameList.add("西瓜");
        nameList.add("火龙果");
        adaptor=new MyAdaptor(this,R.layout.list_item,nameList);
        listView.setAdapter(adaptor);
    }

    public void confirm(View view){
        if(adaptor.getList().size()==0){
            chooseResult.setText("");
        }
        else {
            chooseResult.setText(adaptor.getList().toString());
        }
    }
}
           

主布局以及ListView子布局很简单,这里就直接给出了

<?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="aoto.com.commonwidgetandlayout.basic_widget.checkedTextView.CTextViewActivity">

    <TextView
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp"
        android:textSize="25sp"
        android:text="请选择您喜欢的水果:"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:background="@drawable/rectangle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    <ListView
        android:layout_marginTop="10dp"
        android:layout_marginLeft="50dp"
        android:layout_marginRight="50dp"
        android:layout_marginBottom="10dp"
        android:id="@+id/name_list_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </ListView>
        <Button
            android:text="Sure"
            android:onClick="confirm"
            android:textAllCaps="false"
            android:layout_marginBottom="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
    
    <TextView
        android:gravity="center_horizontal"
        android:textSize="20sp"
        android:id="@+id/choose_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
           
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <CheckedTextView
        android:textSize="25sp"
        android:id="@+id/checked_textView"
        android:checkMark="@drawable/checked_text_view_back"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="CheckedTextView" />
</LinearLayout>
           

这里很多都是关于ListView的知识,唯一用到的CheckedTextView的API就是toggle(),难得用到,我们就把它的源码拿出来看一下吧:

public void toggle() {
        setChecked(!mChecked);
    }
           

超级简单,就是实现这个控件的状态置反操作。关于这个示例的细节就不解释,毕竟还是很简单的。这里我们ListView的子条目布局是一个LinearLayout中放置了一个CheckedTextView实现的。这个时候我们对ListView设置:

listView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {

            }
        });
           

在实际的操作中,我们是获取不到这个事件的,原因很简单,这个监听针对的是ListView子布局View实现了Checkable接口的。我们在上面实际上做了一个错误的示范,因为布局中就一个View,我们为什么不直接用CheckedTextView做ListView子项了,并且其还实现Chackable接口,配合ListView的API就可以实现单选或者多选的操作了。下面我们就按照这个思路来实现一下:

  • 第一步,更换适配器代码
package aoto.com.commonwidgetandlayout.basic_widget.checkedTextView;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;

import java.util.ArrayList;
import java.util.List;

import aoto.com.commonwidgetandlayout.R;

/**
 * author:why
 * created on: 2019/5/14 16:58
 * description:
 */
public class MyAdaptorTest extends ArrayAdapter<String> {

    private static final String TAG = "MyAdaptorWhy";
    private Context context;
    private ArrayList<String> resultList;
    public MyAdaptorTest(@NonNull Context context, int resource, List<String> list) {
        super(context, resource,list);
        this.context = context;
        resultList=new ArrayList();
    }

    @NonNull
    @Override
    public View getView(final int position, @Nullable View convertView, @NonNull ViewGroup parent) {

        View view;
        final ViewHolder holder;
        if (convertView == null) {
            view = new CheckedTextView(context);
            holder=new ViewHolder();
            holder.checkedTextView= (CheckedTextView) view;
            view.setTag(holder);
        } else {
            //布局缓存处理
            view = convertView;
            holder = (ViewHolder) view.getTag();
        }
        String str = getItem(position);
        holder.checkedTextView.setText(str);
        holder.checkedTextView.setCheckMarkDrawable(R.drawable.checked_text_view_back);
        holder.checkedTextView.setTextSize(25);
        return view;
    }

    class ViewHolder {
        CheckedTextView checkedTextView;
    }

    public ArrayList<String> getList(){
        return resultList;
    }
}
           
  • 第二步,更换控制层代码
package aoto.com.commonwidgetandlayout.basic_widget.checkedTextView;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CheckedTextView;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

import aoto.com.commonwidgetandlayout.R;

/**
 * @author why
 * @date 2019-5-14 15:05:23
 */
public class CTextViewTestActivity extends AppCompatActivity {

    private static final String TAG = "CTextViewActivityWhy";
    CheckedTextView textView;
    ListView listView;
    TextView chooseResult;
    MyAdaptorTest adaptor;
    List<String> record = new ArrayList();
    ArrayList<String> nameList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.checked_text_view_test);
        chooseResult = findViewById(R.id.choose_result);
        listView = findViewById(R.id.name_list_view);
        nameList.add("苹果");
        nameList.add("香蕉");
        nameList.add("菠萝");
        nameList.add("西瓜");
        nameList.add("火龙果");
        adaptor = new MyAdaptorTest(this, 0, nameList);
        listView.setAdapter(adaptor);
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        //listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                chooseResult.setText(nameList.get(position));//单选显示

                //多选显示
//                if (record.contains(nameList.get(position))) {
//                    record.remove(nameList.get(position));
//                } else {
//                    record.add(nameList.get(position));
//                }
//
//                if (record.size() == 0) {
//                    chooseResult.setText("");
//                } else {
//                    chooseResult.setText(record.toString());
//                }
            }
        });
    }
}
           

(1)我们首先在自定义适配器中的getView方法中直接返回一个CheckedTextView实例

(2)然后在调用ListView的setChoiceMode()设置选择模式

/**
 * Defines the choice behavior for the List. By default, Lists do not have any choice behavior
 * ({@link #CHOICE_MODE_NONE}). By setting the choiceMode to {@link #CHOICE_MODE_SINGLE}, the
 * List allows up to one item to  be in a chosen state. By setting the choiceMode to
 * {@link #CHOICE_MODE_MULTIPLE}, the list allows any number of items to be chosen.
 *
 * @param choiceMode One of {@link #CHOICE_MODE_NONE}, {@link #CHOICE_MODE_SINGLE}, or
 * {@link #CHOICE_MODE_MULTIPLE}
 */
           

(3)设置AdapterView.OnItemClickListener实现子项选择监听事件获取数据

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                chooseResult.setText(nameList.get(position));//单选显示
            }
        });
           

单选和多选的运行结果如下所示:

Android控件与布局——基础控件CheckedTextView
Android控件与布局——基础控件CheckedTextView

可见,使用CheckedTextView配合ListView实现单选与多选的功能我们实现了。好了,到这里,关于CheckedTextView我们也就介绍完了。

上一篇:RadioButton     下一篇:Spinner

注:欢迎扫码关注

Android控件与布局——基础控件CheckedTextView