【问题标题】:How to highlight or check selected list items如何突出显示或检查选定的列表项
【发布时间】:2017-01-02 12:22:21
【问题描述】:

我应该如何实现 Java 或 XML 代码以在 Android 中的多选模式模式下突出显示(或显示复选框)列表行或网格项,以便与上下文操作栏一起使用?

我已经实现了上下文操作栏和 ListView/GridView,我可以选择它们并在所选项目上运行功能,但是除了在您长按列表行/项目时短暂突出显示之外没有视觉反馈它,它在释放时消失。

我的第一个想法是在适配器中设置行/项目的背景颜色,但我似乎无法让它工作。我也尝试了这个问题的公认答案所建议的解决方案:Android ListView Multi-Choice don't show highlight after chlicking,但它对我的 ListView 和 GridView 的行为没有任何影响。

我最感兴趣的是根据材料设计指南和/或最常见的方式了解执行此操作的标准方式。提前感谢您提供任何建议或解决方案。

编辑

我尝试了 Redman 的答案(实际上与它类似,因为我使用的是上下文动作模式和多项选择侦听器)但我没有得到任何结果。这是我在监听器中所做的:

public void onItemCheckedStateChanged(ActionMode actionMode, int i, long id, boolean checked) {
            if (checked) {
                selectedItems.add(listAdapter.getItem(i));
                ((CheckBox) listAdapter.getView(i,null,listView).findViewById(R.id.listCheckBox)).setChecked(true);
            }
            else {
                selectedItems.remove(listAdapter.getItem(i));
                ((CheckBox) listAdapter.getView(i,null,listView).findViewById(R.id.listCheckBox)).setChecked(false);
            }
        }

它运行没有错误,但对复选框没有任何作用,所以我不确定问题是什么。非常感谢任何帮助。

【问题讨论】:

  • listview 有一个属性 app:selector。尝试使用它,为此,您必须在可绘制文件夹中创建一个 xml 文件,其中包含所选的 true 或默认 false 属性,您可以在其中分配颜色
  • @Mohammad 您能否向我们提供预期的屏幕截图和当前的工作屏幕截图,以便更清楚地解释您的期望。

标签: android listview gridview contextual-action-bar multichoiceitems


【解决方案1】:

好的多选你需要模型,适配器。所以你必须制作自定义列表视图。我在下面给出了一个例子。你只需要将 markAttendance_detail(TextView) 替换为复选框,如果是“P”设置复选框,请检查其他未选中。如果您在这方面遇到任何问题,请告诉我。

Adaper 类-->

public class AttendanceAdapter extends ArrayAdapter {

    List list = new ArrayList();

    static class DataHolder {
        TextView rollNo_detail,studentName_detail,markAttendance_detail;
    }

    public AttendanceAdapter(Context context, int resource) {
        super(context, resource);
    }
    @Override
    public void add(Object object) {
        super.add(object);
        list.add(object);
    }
    @Override
    public int getCount() {
        return this.list.size();
    }

    @Override
    public Object getItem(int position) {
        return this.list.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row;
        row = convertView;
        final DataHolder dataHolder;
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            row = inflater.inflate(R.layout.attendance_list, parent, false);
            dataHolder = new DataHolder();

            dataHolder.rollNo_detail=(TextView)row.findViewById(R.id.student_rollno);
            dataHolder.studentName_detail=(TextView)row.findViewById(R.id.student_name);
            dataHolder.markAttendance_detail=(TextView)row.findViewById(R.id.mark_attendance);
            dataHolder.markAttendance_detail.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    AttendanceModel model=(AttendanceModel) dataHolder.markAttendance_detail.getTag();
                    String att=model.getAttendance().toString();
                    if (model.isSelected()==false){
                        model.setSelected(true);
                        dataHolder.markAttendance_detail.setText("P");
                    }else if (model.isSelected()==true){
                        model.setSelected(false);
                        dataHolder.markAttendance_detail.setText("A");
                    }
                }

            });
            row.setTag(dataHolder);
            dataHolder.markAttendance_detail.setTag(list.get(position));

        }
        else {
            dataHolder = (DataHolder) row.getTag();
            ((DataHolder) row.getTag()).markAttendance_detail.setTag(list.get(position));

        }
        AttendanceModel model = (AttendanceModel) this.getItem(position);

        dataHolder.rollNo_detail.setText(model.getRoll_no());
        dataHolder.studentName_detail.setText(model.getStudent_name());
        if (model.isSelected()==true){
           dataHolder.markAttendance_detail.setText("P");
       }else if (model.isSelected()==false){
            dataHolder.markAttendance_detail.setText("A");
        }
        return row;
    }

模型应该是这样的-->

public class AttendanceModel {
    private String roll_no;
    private String student_name;
    private String attendance;
    private boolean selected;
    public AttendanceModel(String roll_no,String student_name,String attendance){
        this.roll_no=roll_no;
        this.selected=true;
        this.student_name=student_name;
        this.attendance=attendance;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }

    public String getRoll_no() {
        return roll_no;
    }

    public void setRoll_no(String roll_no) {
        this.roll_no = roll_no;
    }

    public String getStudent_name() {
        return student_name;
    }

    public void setStudent_name(String student_name) {
        this.student_name = student_name;
    }

    public String getAttendance() {
        return attendance;
    }

    public void setAttendance(String attendance) {
        this.attendance = attendance;
    }
}

而Activity应该是这样的-->

public class Attendance_Page extends AppCompatActivity {
    ListView listView;
   AttendanceModel model;
    AttendanceAdapter attendanceAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_atendance_page);
        listView= (ListView) findViewById(R.id.attendancepage_list_view);
    attendanceAdapter=new AttendanceAdapter(getApplicationContext(),R.layout.attendance_list);
       listView.setAdapter(attendanceAdapter);
        for (int i=1;i<=10;i++){
            model=new AttendanceModel("1","Aryan","P");
            attendanceAdapter.add(model);
        }
    }
}

从我的角度来看,如果不让我知道,这可能是解决方案。

【讨论】:

    【解决方案2】:

    “我最感兴趣的是根据材料设计指南和/或最常见的方式了解执行此操作的标准方式。”

    我不确定我的答案是材料设计还是通用,但我已经完成了基于 Google“照片”应用中的选择处理的 GridView。我已经对其进行了测试,并且知道它将包括一个突出显示的边框和一个“复选框”。

    ** 免责声明 **

    我考虑过使用选择器,但如果您的视图滚动,似乎会出现问题(请参阅this)。另外,我使用了一个自定义复选框(实际上只是两个不同的可绘制对象),部分原因是this。此外,这个答案基本上只是在纵向模式下处理手机。需要添加更多来处理不同的配置(屏幕尺寸、方向等)

    这里有很多,但就像我说的,我已经测试过了。整个项目已发布到GitHub

    1、在MainActivity onCreate()

    mList = new ArrayList<>();
    
    // fill your list here
    
    mAdapter = new GridAdapter(getApplicationContext(), R.layout.grid_item, mList);
    GridView gridView = (GridView)findViewById(R.id.grid_view);
    gridView.setAdapter(mAdapter);
    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            Log.d(TAG, "item clicked = " + i);
            boolean isSelected = mList.get(i).isSelected();
            mList.get(i).setSelected(!isSelected);
    
            mAdapter.notifyDataSetChanged();
        }
    });
    

    接下来,覆盖适配器中的 getView()(我使用的是 ArrayAdapter)

    @NonNull
    @Override
    public View getView(int position, View convertView, @NonNull ViewGroup parent) {
    
        RelativeLayout itemLayout;
    
        GridItem gridItem = (GridItem)getItem(position);
    
        // use existing Views when we can
        if(convertView == null) {
            LayoutInflater inflater = (LayoutInflater)
                    getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            itemLayout = (RelativeLayout) inflater.inflate(R.layout.grid_item, null);
        } else {
            itemLayout = (RelativeLayout) convertView;
        }
    
        // get your bitmap or list item etc. here
        BitmapDrawable bitmap = gridItem.getBitmap();
        ImageView imageView = (ImageView)itemLayout.findViewById(R.id.image_view);
        imageView.setBackground(bitmap);
    
        if(gridItem.isSelected()) {
            final int PADDING = 16;
    
            Log.d(TAG, "position " + position + " is selected");
            itemLayout.findViewById(R.id.image_frame).setPadding(PADDING, PADDING, PADDING, PADDING);
            itemLayout.findViewById(R.id.custom_check_box)
                    .setBackgroundResource(R.drawable.custom_check_box_selected);
        } else {
            Log.d(TAG, "postion " + position + " is NOT selected");
            itemLayout.findViewById(R.id.image_frame).setPadding(0,0,0,0);
            itemLayout.findViewById(R.id.custom_check_box)
                    .setBackgroundResource(R.drawable.custom_check_box_unselected);
        }
        return itemLayout;
    }
    

    这是 GridItem 类的核心,省略了 getter 和 setter。

    public class GridItem {
    
        private BitmapDrawable bitmap = null;
        private boolean isSelected = false;
    
        public GridItem(BitmapDrawable bitmap) {
            this.bitmap = bitmap;
        }
    }
    

    Java 就是这样。现在来一些xml

    grid_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"
        >
        <FrameLayout
            android:layout_width="140dp"
            android:layout_height="140dp"
            android:id="@+id/image_frame"
            >
            <!-- view for the main image -->
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:scaleType="center"
                android:background="@android:color/white"
                android:id="@+id/image_view"
                />
        </FrameLayout>
    
        <!-- view for the 'checkbox' in upper left corner -->
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="2dp"
            android:src="@drawable/custom_check_box_unselected"
            android:id="@+id/custom_check_box"
            />
    </RelativeLayout>
    

    这将进入 content_main.xml 或 activity_main.xml 等。

    <GridView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="2"
        android:verticalSpacing="10dp"
        android:horizontalSpacing="20dp"
        android:stretchMode="columnWidth"
        android:gravity="center"
        android:id="@+id/grid_view"
        >
    </GridView>
    

    现在你的可绘制文件夹有 2 个文件。

    custom_check_box_unselected.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:height="20dp"
        android:width="20dp"
    
        android:viewportWidth="400"
        android:viewportHeight="400">
    
        <!-- the outside box -->
        <!-- top line & top left corner -->
        <path android:pathData="M 340 30 H 62 c -20 0 -35 15 -35 35 "
            android:strokeColor="#000000" android:strokeWidth="20" />
    
        <!-- left line & bottom left corner -->
        <path android:pathData="M 27 64 v271 c0 20 15 35 35 35 "
            android:strokeColor="#000000" android:strokeWidth="20" />
    
        <!-- bottom line & bottom right corner -->
        <path android:pathData="M 60 370 h275 c20 0 35 -15 35 -35"
            android:strokeColor="#000000" android:strokeWidth="20" />
    
        <!-- right line & top right corner -->
        <path android:pathData="M 370 336 v -271 c0 -20 -15 -35 -35  -35"
            android:strokeColor="#000000" android:strokeWidth="20" />
    </vector>
    

    custom_check_box_selected.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:height="20dp"
        android:width="20dp"
    
        android:viewportWidth="400"
        android:viewportHeight="400">
    
        <!-- the outside box -->
        <path android:pathData="M 340 30 H 62 c -20 0 -35 15 -35 35
                v271 c0 20 15 35 35 35
                h275 c20 0 35 -15 35 -35
                v -271 c0 -20 -15 -35 -35  -35 "
            android:fillColor="#FDD835"  android:strokeColor="#000000" android:strokeWidth="20" />
    
        <!-- the check mark -->
        <path android:pathData="M 140 320 l -100 -100 25 -30
                l 75 75 l 190 -190
                l 25 30 l -190 190"
            android:fillColor="#000000"  android:strokeColor="#000000" android:strokeWidth="2" />
    </vector>
    

    【讨论】:

    • 能否也添加 GridItem 类? (只是类的核心代码)谢谢。
    • @Gary99 能否请您发布 GridItemGridAdapter 的完整代码,集成时有点混乱。
    • @JayRathodRJ 我已将完整项目发布到GitHub
    【解决方案3】:

    您可以通过以下方式在列表视图中显示多选复选框

    在列表子 xml 中添加一个复选框并在 xml 中将其设置为可点击 false

     android:clickable="false"
    

    并为您的列表 OnItemSelectedListner 保留此

     ArrayList<Integer> listPositionsSaveArray= new ArrayList<Integer>(); 
    
      listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    
                        CheckBox presentCheckBox=(CheckBox)view.findViewById(R.id.checkbox__list);
    
                        if(presentCheckBox.isChecked()){
                              presentCheckBox.setChecked(false);
                              listPositionsSaveArray.removeAll(Arrays.asList(position+1));
                        }
                        else{
                        presentCheckBox.setChecked(true);
                        listPositionsSaveArray.add(position+1);
                        }
    
    
                }
            });
    

    列表视图的所有选定位置现在都在listPositionsSaveArray

    【讨论】:

      【解决方案4】:

      据我了解,您希望在用户选中该复选框时更改列表视图行颜色..

      listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
          @Override
          public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
      
              for (int j = 0; j < adapterView.getChildCount(); j++)
                  adapterView.getChildAt(j).setBackgroundColor(Color.TRANSPARENT);
      
              // change the background color of the selected element
              view.setBackgroundColor(Color.LTGRAY);
      });
      

      您可以根据您的要求使用您的逻辑来实现这种不断变化的颜色

      【讨论】:

        【解决方案5】:

        这很简单。在布局文件中,在 ListView 中使用此属性:

        android:choiceMode="singleChoice"
        android:listSelector="#666666"
        

        如果您想以编程方式执行此操作,请尝试以下操作:

        listView.setSelector(Drawable selector)
        
        listView.setSelector(int resourceId)
        
        listview.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
        

        如果您想要多选,请使用AbsListView.CHOICE_MODE_MULTIPLE

        【讨论】:

        • 这不是我的问题的答案。您在这里所做的只是更改选择器的颜色。请阅读问题。
        • 我给你一段代码,让我看看。
        猜你喜欢
        • 2021-10-29
        • 2013-02-24
        • 1970-01-01
        • 2012-02-02
        • 1970-01-01
        • 2021-10-29
        • 1970-01-01
        • 2018-11-10
        • 2013-12-22
        相关资源
        最近更新 更多