Android Studio新手开发第二十二天

目录

列表视图ListView

焦点抢占问题及解决方式

列表视图ListView

列表类视图是 Android 开发中最重要和最常用的组件之一,用于展示大量结构化数据。ListView与Spinner一样通过setAdapter方法设置列表项的数据适配器,但它设置监听器的方法却不同。它通过调用方法setOnItemClickListener设置列表项的点击监听器OnItemClickListener,调用方法setOnitemLongClickListener设置列表项的长按监听器OnItemLongClickListener。列表视图ListView还新增了几个属性以及对应的方法。属性divider指定分割线的图形若不需要分割线只需将该属性的值设为"@null",其对应的方法为setDivider;属性dividerHeight指定分割线的高度,对应方法为setDividerHeight;属性listSelector指定列表项的按压背景,其对应方法为setSelector。代码示例如下,

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=".SeniorWidget.ListViewActivity">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

button_selector.xml的代码如下。

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/teal_200" android:state_pressed="true"/>
    <item android:drawable="@color/green" />
</selector>

部分Java代码如下,数据适配器的内容与下拉框中的用法是一样的,不同在于属性以及对应方法的使用,还有监听器的不同。

java 复制代码
public class ListViewActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {

    private int[] image_id = {R.drawable.one, R.drawable.two, R.drawable.three, R.drawable.four, R.drawable.five,
            R.drawable.six, R.drawable.seven, R.drawable.eight, R.drawable.nine, R.drawable.zero};
    private Integer[] number = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
    private String[] number_english = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "zero"};

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

        ListView listView = findViewById(R.id.listView);
        List<NumberInfo> numberInfoList = getList();

        listView.setAdapter(new MyBaseAdapter(this, numberInfoList));
        listView.setSelection(0);
        listView.setDivider(getDrawable(R.drawable.image_3));
        listView.setDividerHeight(5);
        listView.setSelector(R.drawable.button_selector);

        listView.setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
        if (adapterView.getId() == R.id.listView) {
            Toast.makeText(this,String.format("选中了第%d项",i),Toast.LENGTH_SHORT).show();
        }
    }

    public List<NumberInfo> getList() {
        List<NumberInfo> numberInfoList = new ArrayList<NumberInfo>();
        for (int i = 0; i < number.length; i++) {
            NumberInfo numberInfo = new NumberInfo();
            numberInfo.setImage_id(image_id[i]);
            numberInfo.setNumber(number[i]);
            numberInfo.setNumber_english(number_english[i]);
            numberInfoList.add(numberInfo);
        }
        Log.e(TAG, "getList: ");
        return numberInfoList;
    }

    class NumberInfo {
        private int image_id;
        private int number;
        private String number_english;

        public int getImage_id() {
            return image_id;
        }

        public void setImage_id(int image_id) {
            this.image_id = image_id;
        }

        public int getNumber() {
            return number;
        }

        public void setNumber(int number) {
            this.number = number;
        }

        public String getNumber_english() {
            return number_english;
        }

        public void setNumber_english(String number_english) {
            this.number_english = number_english;
        }
    }

    class MyBaseAdapter extends BaseAdapter {
        private List<NumberInfo> numberInfoList;
        private Context mcontext;

        public MyBaseAdapter(Context context, List<NumberInfo> list) {
            super();
            numberInfoList = list;
            mcontext = context;
        }

        @Override
        public int getCount() {
            return numberInfoList.size();
        }

        @Override
        public Object getItem(int i) {
            return numberInfoList.get(i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder;
            if (view == null) {
                viewHolder = new ViewHolder();
                view = LayoutInflater.from(mcontext).inflate(R.layout.item_base, null);
                viewHolder.imageView = view.findViewById(R.id.imageView);
                viewHolder.textView_1 = view.findViewById(R.id.textView_1);
                viewHolder.textView_2 = view.findViewById(R.id.textView_2);
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }

            NumberInfo numberInfo = numberInfoList.get(i);
            viewHolder.imageView.setImageResource(numberInfo.getImage_id());
            viewHolder.textView_1.setText(String.format("%d", numberInfo.getNumber()));
            viewHolder.textView_2.setText(numberInfo.getNumber_english());
            viewHolder.imageView.requestFocus();
            return view;
        }

        final class ViewHolder {
            public ImageView imageView;
            public TextView textView_1;
            public TextView textView_2;
        }
    }
}

效果图如下,可以看到列表视图能够展示全部的数据项,这与下拉框不一样,下拉框在选择后只能展示一项的内容。

焦点抢占问题及解决方式

如果在列表项中有按钮或者编辑框这类控件,当发生点击事件时这类控件会抢占焦点导致列表项的点击监听器失效。为了解决该问题,可以在列表项的布局文件中的的根节点添加属性descendantFocusability并设置其值或者在Java代码中调用方法setdescendantFocusability设置。该属性有三种取值,如下表所示说明。

|-------------------|------------------------------------|----------------------------------|
| 属性取值 | 代码中的方法参数取值 | 说明 |
| beforeDescendants | ViewGroup.FOCUS_BEFORE_DESCENDANTS | 视图组优先:ViewGroup 先于子视图获取焦点 |
| afterDescendants | ViewGroup.FOCUS_AFTER_DESCENDANTS | 子视图优先:子视图先于 ViewGroup 获取焦点 |
| blocksDescendants | ViewGroup.FOCUS_BLOCK_DESCENDANTS | 阻止子视图:ViewGroup 获取焦点,阻止子视图获取 |

代码示例如下,页面布局文件不变。

下面为item_listview.xml中的代码,在原来的列表项布局中新加了一个按钮并且在布局的根结点添加了属性descendantFocusability并且取值为blocksDescendants。

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:descendantFocusability="blocksDescendants">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_weight="1"
        android:src="@drawable/image_3"/>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="100dp"
        android:layout_weight="2"
        android:orientation="vertical">
        <TextView
            android:id="@+id/textView_1"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:textSize="17sp"
            android:textColor="#1269db"
            android:text="@string/app_name"/>
        <TextView
            android:id="@+id/textView_2"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:textSize="17sp"
            android:text="@string/app_name"/>
    </LinearLayout>

    <Button
        android:id="@+id/button"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_gravity="center"
        android:text="Button" />

</LinearLayout>

Java代码的不同主要在于适配器中,在类ViewHolder中添加了一个按钮button用于获取按钮实例,在方法getView中改变在于与按钮相关的部分,如获取按钮实例以及设置按钮监听器,其余基本不变。

java 复制代码
   class MyBaseAdapter extends BaseAdapter {
        private List<NumberInfo> numberInfoList;
        private Context mcontext;

        public MyBaseAdapter(Context context, List<NumberInfo> list) {
            super();
            numberInfoList = list;
            mcontext = context;
        }

        @Override
        public int getCount() {
            return numberInfoList.size();
        }

        @Override
        public Object getItem(int i) {
            return numberInfoList.get(i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder;
            if (view == null) {
                viewHolder = new ViewHolder();
                view = LayoutInflater.from(mcontext).inflate(R.layout.item_listview, null);
                viewHolder.imageView = view.findViewById(R.id.imageView);
                viewHolder.textView_1 = view.findViewById(R.id.textView_1);
                viewHolder.textView_2 = view.findViewById(R.id.textView_2);
                viewHolder.button = view.findViewById(R.id.button);
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }

            NumberInfo numberInfo = numberInfoList.get(i);
            viewHolder.imageView.setImageResource(numberInfo.getImage_id());
            viewHolder.textView_1.setText(String.format("%d", numberInfo.getNumber()));
            viewHolder.textView_2.setText(numberInfo.getNumber_english());
            viewHolder.button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(mcontext,String.format("点击了第%d项的按钮!",i+1),Toast.LENGTH_SHORT).show();
                }
            });
            viewHolder.imageView.requestFocus();
            return view;
        }

        final class ViewHolder {
            public ImageView imageView;
            public TextView textView_1;
            public TextView textView_2;
            public Button button;
        }
    }

效果图如下,可以看到按钮并没有抢占列表项的焦点,两者的监听器能够正常运行。

相关推荐
用户41659673693554 小时前
Jetpack Compose 中实现带圆角边框的单词级富文本效果(分词与布局实践)
android
顾林海4 小时前
Android UI优化:让你的APP从“卡顿掉帧”到“丝滑如德芙”
android·面试·性能优化
啊森要自信5 小时前
【MySQL 数据库】MySQL用户管理
android·c语言·开发语言·数据库·mysql
黄毛火烧雪下5 小时前
(二)Flutter插件之Android插件开发
android·flutter
2501_916007475 小时前
iOS 上架技术支持全流程解析,从签名配置到使用 开心上架 的实战经验分享
android·macos·ios·小程序·uni-app·cocoa·iphone
sakoba7 小时前
MySQL的json处理相关方法
android·学习·mysql·json
神仙别闹7 小时前
Android 端 2D 横屏动作冒险类闯关游戏
android·游戏
坏小虎7 小时前
Android App Startup 库使用说明文档,初始化不再用Application了...
android
暮色驶过苍茫14 小时前
VSCode 配置 SSH 远程连接
ide·vscode·ssh