在Android上,我希望用户能够从列表中选择多个行。我读到可以使用
RecyclerView
的 SelectionTracker
来启用列表项选择。但是所有的代码示例都是用Kotlin编写的。请问有没有Java的 SelectionTracker
示例?RecyclerView
的 SelectionTracker
来启用列表项选择。但是所有的代码示例都是用Kotlin编写的。请问有没有Java的 SelectionTracker
示例?这里是一个设置菜单,用户可以选择多个设置。要开始选择,用户必须长按任何设置。然后他们可以点击任何设置来进行更多选择。
活动
package com.locuslabs.android.sdk;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.selection.ItemDetailsLookup;
import androidx.recyclerview.selection.Selection;
import androidx.recyclerview.selection.SelectionPredicates;
import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.selection.StableIdKeyProvider;
import androidx.recyclerview.selection.StorageStrategy;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.gson.Gson;
import com.locuslabs.android.sdk.api.ConfigurationExperiments;
import com.locuslabs.android.sdk.api.MapExperiments;
import com.locuslabs.android.sdk.api.MapViewExperiments;
import com.locuslabs.android.sdk.api.PositionExperiments;
import com.locuslabs.android.sdk.api.VenueExperiments;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
public class SettingsActivity extends Activity {
private static final String TAG = "SettingsActivity";
SelectionTracker<Long> selectedSettingTracker;
private RecyclerView settingsRecyclerView;
private List<String> listOfUsableApis;
private ApiSettings mApiSettings;
private void setApiSettings(List<String> settingNamesSelected) {
for (String settingName : settingNamesSelected) {
if (settingName.equals(getResources().getString(R.string.api_setting_draw_line)))
mApiSettings.mDrawLine = true;
if (settingName.equals(getResources().getString(R.string.api_setting_search)))
mApiSettings.mLogSearch = true;
/* omitted rest of options for brevity */
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApiSettings = new ApiSettings();
setContentView(R.layout.activity_settings);
settingsRecyclerView = findViewById(R.id.settingsRecyclerView);
settingsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
Button backButton = findViewById(R.id.settings_back_button);
Button saveButton = findViewById(R.id.settings_apply_button);
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setApiSettings(getSettingNamesSelected());
Intent intent = new Intent();
intent.putExtra("apiSettings", new Gson().toJson(mApiSettings));
setResult(RESULT_OK, intent);
finish();
}
});
listOfUsableApis = /* omitted for brevity */
final SettingsAdapter settingsAdapter = new SettingsAdapter();
settingsRecyclerView.setAdapter(settingsAdapter);
// Handle selection of settings
selectedSettingTracker = new SelectionTracker.Builder<Long>(
"selectedSettingTrackerId",
settingsRecyclerView,
new StableIdKeyProvider(settingsRecyclerView),
new SettingsDetailsLookup(),
StorageStrategy.createLongStorage()
).
withSelectionPredicate(SelectionPredicates.<Long>createSelectAnything()).
build();
}
private List<String> getSettingNamesSelected() {
Selection<Long> settingsSelection = selectedSettingTracker.getSelection();
Iterator<Long> settingSelectionIterator = settingsSelection.iterator();
List<String> settingNamesSelected = new ArrayList<>();
while (settingSelectionIterator.hasNext()) {
Long settingSelectionId = settingSelectionIterator.next();
String settingNameSelected = listOfUsableApis.get(settingSelectionId.intValue());
settingNamesSelected.add(settingNameSelected);
}
return settingNamesSelected;
}
public static class ApiSettings {
public boolean mDrawLine = false;
public boolean mWalkSimulator = false;
/* omitted most options for brevity */
public ApiSettings() {
}
}
private class SettingsAdapter extends RecyclerView.Adapter<SettingsAdapter.SettingViewHolder> {
public SettingsAdapter() {
setHasStableIds(true);
}
@NonNull
@Override
public SettingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
TextView textView = (TextView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.setting_list_item, parent, false);
SettingViewHolder settingViewHolder = new SettingViewHolder(textView);
return settingViewHolder;
}
@Override
public void onBindViewHolder(@NonNull SettingViewHolder holder, final int position) {
holder.textView.setText(listOfUsableApis.get(position));
holder.textView.setActivated(selectedSettingTracker.isSelected((long) position));
holder.position = position;
}
@Override
public int getItemCount() {
return listOfUsableApis.size();
}
@Override
public long getItemId(int position) {
return Long.valueOf(position);
}
public class SettingViewHolder extends RecyclerView.ViewHolder {
public int position;
public TextView textView;
public SettingViewHolder(TextView v) {
super(v);
textView = v;
}
}
}
private class SettingsDetailsLookup extends ItemDetailsLookup<Long> {
@Nullable
@Override
public ItemDetails<Long> getItemDetails(@NonNull MotionEvent event) {
View view = settingsRecyclerView.findChildViewUnder(event.getX(), event.getY());
if (view != null) {
final RecyclerView.ViewHolder viewHolder = settingsRecyclerView.getChildViewHolder(view);
if (viewHolder instanceof SettingsAdapter.SettingViewHolder) {
final SettingsAdapter.SettingViewHolder settingViewHolder = (SettingsAdapter.SettingViewHolder) viewHolder;
return new ItemDetailsLookup.ItemDetails<Long>() {
@Override
public int getPosition() {
return viewHolder.getAdapterPosition();
}
@Nullable
@Override
public Long getSelectionKey() {
return Long.valueOf(settingViewHolder.position);
}
};
}
}
return null;
}
}
}
布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:baselineAligned="false"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#454545"
android:weightSum="100">
<Button
android:id="@+id/settings_back_button"
android:background="#454545"
android:drawableStart="@drawable/arrow_white"
android:drawableLeft="@drawable/arrow_white"
android:layout_gravity="start"
android:layout_width="@dimen/ll_mdu_10"
android:layout_height="@dimen/ll_mdu_10"
android:layout_weight="5"/>
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="90"
/>
<Button
android:id="@+id/settings_apply_button"
android:background="#454545"
android:drawableStart="@android:drawable/ic_menu_save"
android:drawableLeft="@android:drawable/ic_menu_save"
android:layout_gravity="end"
android:layout_width="@dimen/ll_mdu_10"
android:layout_height="@dimen/ll_mdu_10"
android:layout_weight="5"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Long-press for first setting, then tap other settings for multiple selection"
app:layout_constraintBottom_toTopOf="@+id/settingsRecyclerView"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/settingsRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</LinearLayout>
</LinearLayout>
布局设置_list_item.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setting_list_item_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/setting_background"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:textAppearance="?android:attr/textAppearanceListItemSmall" />
背景可绘制设置_background.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/holo_green_dark" android:state_activated="true" />
<item android:drawable="@android:color/white" />
</selector>
参考文献:
https://developer.android.com/guide/topics/ui/layout/recyclerview#select 这篇文档难以阅读,需要一个例子。
https://proandroiddev.com/a-guide-to-recyclerview-selection-3ed9f2381504 Kotlin 例子难以理解。
https://www.youtube.com/watch?v=jdKUm8tGogw&feature=youtu.be&list=PLWz5rJ2EKKc9Gq6FEnSXClhYkWAStbwlC&t=980 Google IO 中提到了这个功能(但是用的是 Kotlin)。
https://medium.com/@Dalvin/android-recycler-view-with-multiple-item-selections-b2af90eb5825 另一个 Java 的例子!