Android ListView 的焦点问题

在项目开发中,在 ListViewItem 中放了一个 CheckBox ,然后就发现了一个重大的问题:

触发不了 ListViewonItemClick()onItemLongClick() 方法

这个问题很严重,因为意味着 ListViewItem 点击不了,然后把 CheckBox 去掉之后又能点击了

所以,问题在于 CheckBox 拦截了这些方法

我们写一个 demo 来复现下

  1. 创建一个 空的 Android 项目 cn.twle.android.ListViewFocus

  2. 修改 activity_main.xml 添加一个 ListView

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp" 
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    
  3. 定义列表中每一行的布局,在 res/layout 目录下新建一个文件 listview_item.xml

    <?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:padding="8dp"
        android:orientation="horizontal">
    
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="8dp"
            android:textColor="#1D1D1C"
            android:textSize="20sp" 
            android:layout_weight="3" />
    
        <CheckBox
            android:id="@+id/checked"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />
    
        </LinearLayout>
    

    CheckBox 只是一个状态指示器

  4. 修改 MainActivity.java

    package cn.twle.android.listviewfocus;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    import android.widget.SimpleAdapter;
    import android.widget.ListView;
    import android.widget.Toast;
    import android.widget.AdapterView;
    
    import android.view.View;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener  {
    
        private String[] langs = new String[]{
            "Kotlin", 
            "Scala", 
            "Swift",
            "TypeScript",
            "Java",
            "Python",
            "PHP",
            "Perl",
        };
    
        private Boolean[] checkeds = new Boolean[]{
            true,
            false,
            true,
            false,
            true,
            false,
            true,
            false
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            List<Map<String, Object>> listitem = new ArrayList<Map<String, Object>>();
            for (int i = 0; i < langs.length; i++) {
                Map<String, Object> showitem = new HashMap<String, Object>();
                showitem.put("name", langs[i]);
                showitem.put("checked", checkeds[i]);
                listitem.add(showitem);
            }
    
            //创建一个 SimpleAdapter
            SimpleAdapter myAdapter = new SimpleAdapter(getApplicationContext(), listitem, R.layout.listview_item, new String[]{"name", "checked"}, new int[]{R.id.name, R.id.checked});
    
            ListView listView = (ListView) findViewById(R.id.listview);
    
            listView.setAdapter(myAdapter);
            listView.setOnItemClickListener(this);
        }
    
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Toast.makeText(getApplicationContext(),"你点击了第" + position + "项",Toast.LENGTH_SHORT).show();
        }
    
    }
    

运行范例后,点击部分区域没有效果


要怎么办呢 ?

解决办法有两个

  1. 为抢占了控件的组件设置 android:focusable="false" 或调用 setFocusable(false)

    为抢占了控件的组件设置 android:focusable="false" 之后,这个控件就不能再被点击了

    这个方法大部分能行得通,但是,EditText 却不行

    如果为 EditText 设置了 android:focusable="false" ,它可以获取焦点但是一下子又失去了焦点,而且也不会弹出小键盘

    因为它仍然可以点击啊...只是不能获得焦点,获得焦点有两种方式..自动获得和点击获得...

    这时候只能加上 setFocusableInTouchMode(false);

  2. item 根节点设置 android:descendantFocusability="blocksDescendants"

    设置这个属性的意思是禁止事件传递

    这个属性还有其它的值

    说明
    beforeDescendants viewgroup 会优先其子类控件而获取到焦点
    afterDescendants viewgroup 只有当其子类控件不需要获取焦点时才获取焦点
    blocksDescendants viewgroup 会覆盖子类控件而直接获得焦点

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.