将 ListView 项目的状态更改为以编程方式激活?

Change ListView Item's state to activated programmatically?

我有一个带有自定义 UserAdapterListView,其中包含一个 SparseBooleanArray 和当前激活(选定)的 ID。

方法 toggleSelection(position) 从我的 SparseBooleanArray 创建或删除条目。 因此,我可以在 listView.onItemClickListener() 中的 DriverFragment 中调用此方法,结果项目的背景可绘制对象会在单击时发生变化。

现在我想以编程方式预选 DriverSelectionFragment 中的一项。 到目前为止,我可以将它添加到我的 SparseBooleanArray 但在进入片段时背景不会改变。

我错过了什么?我必须通知 listView 吗?我正在 onViewCreated() 中添加所选项目,所以它应该可以工作。

编辑:添加了xml个文件

用户适配器:

package com.example.convictedDriver.Adapters;

import android.content.Context;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.convictedDriver.Database.User;
import com.example.convictedDriver.R;
import com.mikhaellopez.circularimageview.CircularImageView;

import org.jetbrains.annotations.NotNull;

import java.util.List;

public class UserAdapter extends ArrayAdapter<User> {
    // Declare Variables
    private List<User> userList;
    private ViewGroup parent;
    private LayoutInflater inflater;
    private SparseBooleanArray mSelectedItemsIds;

    public UserAdapter(Context context, int resource, List<User> userList) {
        super(context, resource, userList);
        mSelectedItemsIds = new SparseBooleanArray();
        this.userList = userList;
        inflater = LayoutInflater.from(context);
    }

    private class ViewHolder {
        TextView name;
        TextView ratio;
        CircularImageView circularImageView;
    }

    @Override
    public View getView(int position, View view, @NotNull ViewGroup parent) {
        final ViewHolder holder;
        this.parent = parent;
        if(view == null){
            holder = new ViewHolder();
            view = inflater.inflate(R.layout.list_item, null, false);
            // Locate the TextViews and Imageview in list_item.xml
            holder.name = view.findViewById(R.id.user_name_text);
            holder.ratio = view.findViewById(R.id.user_ratio_text);
            holder.circularImageView = view.findViewById(R.id.list_item_imageView);
            view.setTag(holder);
        }else{
            holder = (ViewHolder) view.getTag();
        }
        // Capture position and set to the TextViews and ImageView
        holder.name.setText(userList.get(position).getUsername());
        holder.ratio.setText(String.valueOf((userList.get(position).getRatio())));
        holder.circularImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
        return view;
    }

    @Override
    public void remove(User user){
        userList.remove(user);
        notifyDataSetChanged();
    }

    public List<User> getUserList(){
        return userList;
    }

    // Toggles the selection state of a given item position
    public void toggleSelection(int position) {
        selectView(position, !mSelectedItemsIds.get(position));
        Log.i("Debug", "Position "+position+" changed state from "+!mSelectedItemsIds.get(position)+" to "+
                mSelectedItemsIds.get(position));
    }

    // Removes all selections
    public void removeSelection() {
        mSelectedItemsIds = new SparseBooleanArray();
        notifyDataSetChanged();
    }

    // Helper Class for toggling a specific item position
    private void selectView(int position, boolean value) {
        if (value) {
            mSelectedItemsIds.put(position, value);
        }
        else {
            mSelectedItemsIds.delete(position);
        }
    }

    // Returns the amount of selected items
    public int getCheckedCount() {
        int num = 0;
        for (int i = 0; i < mSelectedItemsIds.size(); i++) {
            if (mSelectedItemsIds.valueAt(i)) {
                num++;
            }
        }
        return num;
    }

    // Returns the SparseBooleanArray for the ListView
    public SparseBooleanArray getSelectedIds() {
        return mSelectedItemsIds;
    }

}

DriverFragment:

package com.example.convictedDriver.Fragments.Drive;

import android.os.Bundle;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.navigation.Navigation;

import com.example.convictedDriver.Adapters.UserAdapter;
import com.example.convictedDriver.Classes.MyListSorter;
import com.example.convictedDriver.Classes.MyToast;
import com.example.convictedDriver.Database.IntegratedDatabase.UserDbHelper;
import com.example.convictedDriver.Database.User;
import com.example.convictedDriver.R;
import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.util.ArrayList;

public class DriveFragment extends Fragment {

    private FloatingActionButton fabContinue;
    private ArrayList<User> userList;
    private ListView listView;
    private UserAdapter adapter;
    private SparseBooleanArray checked;

    public DriveFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_drive, container, false);

        // Getting all the users out of the database and sort them
        UserDbHelper db = UserDbHelper.getInstance(getContext());
        userList = db.getAllUsers();
        MyListSorter.sort(userList, MyListSorter.SortType.RATIO);

        // Locate the ListView and in fragment_drive.xml
        listView = view.findViewById(R.id.drive_listView);
        fabContinue = view.findViewById(R.id.fab_continue);
        return view;
    }

    @Override
    public void onResume() {
        super.onResume();

    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable final Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        // Pass userList to UserAdapter Class
        adapter = new UserAdapter(getContext(), R.layout.list_item, userList);
        // Binds the Adapter to the ListView
        listView.setItemsCanFocus(false);
        listView.setAdapter(adapter);

        checked = adapter.getSelectedIds();
        Toast.makeText(getContext(), "OnViewCreated: "+checked.toString(),Toast.LENGTH_SHORT).show();

        // Capture ListView item click
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // Toggle the ListViewItems State
                adapter.toggleSelection(position);
                Toast.makeText(getContext(), "OnItemClick: "+checked.toString(),Toast.LENGTH_SHORT).show();
            }
        });

        /*
        * Create an array out of the selectedUsers Arraylist and pass it
        * towards DriveSelectionFragment
         */
        fabContinue.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                checked = adapter.getSelectedIds();
                Toast.makeText(getContext(), "OnClickListener: "+checked.toString(),Toast.LENGTH_SHORT).show();
                if(adapter.getCheckedCount() > 2) {
                    User[] userArray = new User[checked.size()];
                    int j = 0;
                    for (int i = (checked.size() - 1); i >= 0; i--){
                        if (checked.valueAt(i)){
                            userArray[j] = adapter.getItem(checked.keyAt(i));
                            j++;
                        }
                    }
                    //listView.clearChoices();
                    adapter.removeSelection();
                    DriveFragmentDirections.ActionDriveFragmentToDriveSelectionFragment action =
                            DriveFragmentDirections.actionDriveFragmentToDriveSelectionFragment(userArray);
                    Navigation.findNavController(v).navigate(action);
                }else{
                    new MyToast(getContext(), "Select at least 3 Users!", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

DriverSelectionFragment:

package com.example.convictedDriver.Fragments.Drive;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import com.example.convictedDriver.Adapters.UserAdapter;
import com.example.convictedDriver.Database.User;
import com.example.convictedDriver.R;

import java.io.File;
import java.util.ArrayList;

public class DriveSelectionFragment extends Fragment {

    private ArrayList<User> selectedDrivers = new ArrayList<>();
    private ArrayList<User> userList = new ArrayList<>();
    private ListView listView;
    private UserAdapter adapter;
    private User driver;
    private View view;
    private SparseBooleanArray checked;

    public DriveSelectionFragment(){
        // Empty constructor is needed
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_drive_selection, container, false);
        listView = view.findViewById(R.id.driveSelection_listView);
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        // Receive an ArrayList as argument, including all the userList
        if(getArguments() != null){
            DriveSelectionFragmentArgs args = DriveSelectionFragmentArgs.fromBundle(getArguments());
            userList = arrayToList(args.getSelectedUsers());
        }

        // Calculate the user with the highest ratio out of the userList
        // and add it to the selectedDrivers ArrayList
        driver = calculateDriver(userList);
        selectedDrivers.add(driver);
        Toast.makeText(getContext(), "Driver: "+driver.getUsername(),Toast.LENGTH_SHORT).show();

        // Initialize listView and set the adapter
        adapter = new UserAdapter(getContext(),R.layout.list_item, userList);
        listView.setItemsCanFocus(false);


        int driverPos = getDriverPosition(userList, driver);
        Toast.makeText(getContext(), "DriverPosition: "+driverPos,Toast.LENGTH_SHORT).show();
        adapter.toggleSelection(getDriverPosition(userList,driver));

        checked = adapter.getSelectedIds();
        Toast.makeText(getContext(), "OnViewCreated: "+checked.toString(),Toast.LENGTH_SHORT).show();

        // Binds the Adapter to the ListView
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // Toggle the ListViewItems State
                adapter.toggleSelection(position);
                Toast.makeText(getContext(), "OnItemClick: "+checked.toString(),Toast.LENGTH_SHORT).show();
            }
        });

    }


    /*
    *
    * Calculates a user out of a given list with the highest ratio
    *
     */
    private User calculateDriver(ArrayList<User> list){
        User currUser = list.get(0);
        for (User user : list){
            if(user.getRatio() >= currUser.getRatio()){
                Log.i("Test", user.getRatio() +">"+ currUser.getRatio());
                currUser = user;
                Log.i("Test", "Changed driver to "+currUser);
            }
        }
        return currUser;
    }

    private int getDriverPosition(ArrayList<User> list, User driver){
        int position = 0;
        for (User user: list) {
            if (user.getId() == driver.getId()){
                return position;
            }else{
                position++;
            }
        }
        return -1;
    }

fragment_drive_selection.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".Fragments.Drive.DriveSelectionFragment">

    <ListView
        android:id="@+id/driveSelection_listView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:divider="@null"
        android:dividerHeight="3dp"
        android:layout_marginVertical="5dp"
        android:choiceMode="multipleChoice"
        android:listSelector="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

list_item.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
    android:foreground="?attr/selectableItemBackground"
    android:background="@drawable/list_item_selector">

    <com.mikhaellopez.circularimageview.CircularImageView
        android:id="@+id/list_item_imageView"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="5dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        app:civ_border="false"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:src="@drawable/avatar_1"/>

    <TextView
        android:id="@+id/user_name_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginStart="8dp"
        android:autoSizeTextType="uniform"
        android:text=""
        android:textColor="@color/colorSpotifyWhite"
        android:textSize="22sp"
        app:layout_constraintBottom_toTopOf="@+id/user_ratio_text"
        app:layout_constraintStart_toEndOf="@+id/list_item_imageView"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="name" />

    <TextView
        android:id="@+id/user_ratio_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginStart="8dp"
        android:text=""
        tools:text="ratio"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/list_item_imageView"
        app:layout_constraintTop_toBottomOf="@id/user_name_text" />

</androidx.constraintlayout.widget.ConstraintLayout>

list_item_selector.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- pressed -->
    <item android:state_enabled="true"
        android:state_pressed="true" android:drawable="@drawable/list_item_background_selected" />
    <!-- focused -->
    <item android:state_enabled="true"
        android:state_focused="true" android:drawable="@drawable/list_item_background_selected" />
    <!-- selected -->
    <item android:state_enabled="true"
        android:state_selected="true" android:drawable="@drawable/list_item_background_selected" />
    <!-- default -->
    <item android:state_enabled="true"
        android:state_checked="true" android:drawable="@drawable/list_item_background_selected" />

    <item android:state_activated="true"
        android:drawable="@drawable/list_item_background_selected" />

    <!-- default -->
    <item android:drawable="@drawable/list_item_background" />
</selector>

当设置 多选模式 时,您必须在 ListView 上使用 setItemChecked 来 select 项目。检查以下内容:

int selctedPosition = getDriverPosition(userList,driver);
adapter.toggleSelection(selctedPosition);

// Binds the Adapter to the ListView
listView.setAdapter(adapter);
listView.setItemChecked(selctedPosition, true);