آموزش های این وب سایت به صورت رایگان در دسترس است. اطلاعات بیشتر
بروز خطا
   [message]
اشتراک در سوال
رای ها
[dataList]

آموزش ActionMode به همراه Recyclerview

amirhossein1376  9 سال پیش  7 سال پیش
+14 0

حالت ActionMode یکی از کاربردی ترین مواردی هست که برای کار با لیست ( انتخاب چندگانه) استفاده میشه و در حال حاضر هم RecyclerView بهترین component برای کار با لیست هستش و میشه گفت کاملا جای لیست ویو رو گرفته 

تو این آموزش قراره این حالت رو برای RecyclerView آموزش بدم . امیدوارم مفید واقع بشه

 

+3 0
به نظرم خیلی فیدبک کم بود! یعنی انقدر غیر کاربردی بود؟! (9 سال پیش)
0 0
دمت گرم.حتما کاربرا حمایت میکنن،من خودم الان این تاپیک رو دیدم.منتظر آموزش های بعدی تون هستیم :) (9 سال پیش)
0 0
صد درصد کاربردی عالی من اینو تو سایتا گشتم چیزی دستگیرم نشد ولی خوشبختانه شما توضیح دادید (7 سال پیش)
 برای این سوال 5 پاسخ وجود دارد. مشاهده پاسخ صحیح
پاسخ به سوال 
amirhossein1376  9 سال پیش
+4 0

 پاسخ صحیح

بخش اول  : ایجاد RecyclerView و ریختن مقادیر تستی در آن :

 مثل قبل یک پروژه در اندروید استودیو ایجاد بکنید .

برید توی فایل (build.gradle(moudel:app و توی قسمت dependencies این دو خط رو اضافه کنید

 
 
compile 'com.android.support:recyclerview-v7:25.0.0'
compile 'com.android.support:cardview-v7:25.0.0'
 

با این کار لایبرری های RecyclerView و CardView به پروژه اضافه شده و قابل استفاده خواهند بود

حالا توی activity_main کدها رو پاک کرده و این کدهارو جایگزین میکنیم

 
 
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
 

یک فایل Layout دیگه ایجاد میکنیم به اسم card.xml با محتویات زیر :

 
 
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="#ffffff"
app:cardCornerRadius="2dp"
app:cardElevation="2dp"
app:cardUseCompatPadding="true">

<TextView
android:gravity="center"
android:minHeight="48dp"
android:id="@+id/txtCardTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000000"/>

</android.support.v7.widget.CardView>
 

کارمون تو بخش xml تموم شده و میریم توی بخش جاوا

ابتدا یک آداپتور برای RecyclerView ایجاد میکنم .  من یک فایل java با نام RecyclerViewAdapter ایجاد میکنم و محتویات زیر رو توش قرار میدم :

 
 
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {

private List<String> mResources;
private Context mContext;

public RecyclerViewAdapter(List<String> resources, Context context) {
mResources = resources;
mContext = context;
}

@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.card, parent, false);
RecyclerViewHolder viewHolder = new RecyclerViewHolder(view);
return viewHolder;
}

@Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.update(mResources.get(position));
}

@Override
public int getItemCount() {
return mResources.size();
}

public class RecyclerViewHolder extends RecyclerView.ViewHolder {

private TextView txtTitle;

public RecyclerViewHolder(View itemView) {
super(itemView);
txtTitle = (TextView) itemView.findViewById(R.id.txtCardTitle);
}

public void update(String text) {
txtTitle.setText(text);
}
}
}
 

تقریبا کار تمومه فقط کافیه بریم و توی اکتیویتیمون RecyclerView رو تعریف کنیم.

من یه سری اطلاعات هم بهش میدم و تستش میکنم.

محتویات MainActivity : 

 
 
public class MainActivity extends AppCompatActivity {

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

List<String> data = new ArrayList<>();

for (int i = 0; i < 60; i++) {
data.add("Some Title Or Description " + i);
}

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(data, this);
LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(manager);

}
}
 

 

خوب تا ایجای کار لیست ما آماده شده و اپ به این شکل دراومد

پاسخ به سوال 
amirhossein1376  9 سال پیش
+5 0

بخش دوم : پیاده سازی ActionMode : 

 اول از همه یه توضیحی بدم 

ببنید من ترجیح دادم کد رو اینطوری بزنم و به شما هم این توصیه رو میکنم که هر وقت CardView ساختید آیدی اون رو ثابت بزارید . به عنوان مثال من همیش card میزارم.دلیلش رو جلوتر میبینیم

اول یه اینترفیس به اسم ClickListener تعریف کنید . این لیسنر برای تشخیص کلیک روی آیتم های RecyclerView استفاده میشه:

public interface ClickListener {
void onItemClicked(int position);

boolean onItemLongClicked(int position);
}

بعد از اینکار نوبت میرسه به ایجاد یک ViewHolder یکتا (BaseViewHolder)  :

بیاید و یک کلاس به اسم BaseViewHolder بسازید . بعدا قراره RecyclerViewHolder و هر ویو هولدر دیگه ای که داریم از BaseviewHolder اکستندز بشن . کد های کلاس BaseViewHolder : 

 
public abstract class BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {

public CardView mCardView;
public ClickListener mListener;
public Context mContext;

public BaseViewHolder(View itemView, ClickListener listener, Context context) {
super(itemView);
this.mListener = listener;
this.mContext = context;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
mCardView = (CardView) itemView.findViewById(R.id.card);
}

@Override
public void onClick(View view) {
if (mListener != null) {
mListener.onItemClicked(getLayoutPosition());
}
}

@Override
public boolean onLongClick(View view) {
if (mListener != null) {
return mListener.onItemLongClicked(getLayoutPosition());
}

return false;
}
}

همون طور که میبینید این کلاس مثل همه کلاس های Base ابسترکت تعریف شده و قابلیت نمونه سازی نداره . همچینین برای CardView همونطور که گفتم از آیدی card استفاده شده و همچین clickListener برای اعضاش تعریف شده!

کار بعدی ایجاد یک کلاس دیگه برای Adapter ماست تا selectable کردن آداپتور انجام بشه .

من اومدم و با استفاده از سورس های موجود و تغییراتی که خودم دادم یه کلاس جمع و جوری بسازم.من اسمش رو گذاشتم BaseAdapter پس شما یک کلاس به اسم BaseAdapter ایجاد کنید و کدهای زیرو رو درون کلاس کپی کنید :

 
public abstract class BaseAdapter<VH extends RecyclerView.ViewHolder, T> extends RecyclerView.Adapter<VH> {

private SparseBooleanArray selectedItems;

protected List<T> mData;
protected Context mContext;
protected ClickListener mClickListener;

public BaseAdapter(Context context, List<T> data, ClickListener listener) {
selectedItems = new SparseBooleanArray();
mClickListener = listener;
mContext = context;
mData = data;
}

public boolean isSelected(int position) {
return getSelectedItems().contains(position);
}

public void toggleSelection(int position) {
if (selectedItems.get(position, false)) {
selectedItems.delete(position);
} else {
selectedItems.put(position, true);
}
notifyItemChanged(position);
}

public void selectItem(int position) {
if (!selectedItems.get(position, false)) {
selectedItems.put(position, true);
}

notifyItemChanged(position);
}

public void deSelectItem(int position) {
if (selectedItems.get(position, false)) {
selectedItems.delete(position);
}

notifyItemChanged(position);
}

public void clearSelection() {
List<Integer> selection = getSelectedItems();
selectedItems.clear();
for (Integer i : selection) {
notifyItemChanged(i);
}
}

public int getSelectedItemCount() {
return selectedItems.size();
}

public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); ++i) {
items.add(selectedItems.keyAt(i));
}
return items;
}

/*****************************************************************************************************************/

public void removeItem(int position) {
mData.remove(position);
notifyItemRemoved(position);
}

private void removeRange(int positionStart, int itemCount) {
for (int i = 0; i < itemCount; ++i) {
mData.remove(positionStart);
}
notifyItemRangeRemoved(positionStart, itemCount);
}

public void removeItems(List<Integer> positions) {
Collections.sort(positions, new Comparator<Integer>() {
@Override
public int compare(Integer lhs, Integer rhs) {
return rhs - lhs;
}
});
while (!positions.isEmpty()) {
if (positions.size() == 1) {
removeItem(positions.get(0));
positions.remove(0);
} else {
int count = 1;
while (positions.size() > count && positions.get(count).equals(positions.get(count - 1) - 1)) {
++count;
}

if (count == 1) {
removeItem(positions.get(0));
} else {
removeRange(positions.get(count - 1), count);
}

for (int i = 0; i < count; ++i) {
positions.remove(0);
}
}
}
}

/******************************************************************************************************/

@Override
public int getItemCount() {
return mData.size();
}

}

 

بعد از همه ی این کارها ساختار RecyclerAdapter تغییر خواهد کرد به این شکل که آداپتور از BaseAdapter و هولدر از BaseViewHolder اکستندز میشه

 
public class RecyclerViewAdapter extends BaseAdapter<RecyclerViewAdapter.RecyclerViewHolder, String> {

public RecyclerViewAdapter(List<String> data, Context context, ClickListener listener) {
super(context, data, listener);
}

@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.card, parent, false);
RecyclerViewHolder viewHolder = new RecyclerViewHolder(view, mClickListener, mContext);
return viewHolder;
}

@Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
if (isSelected(position)) {
holder.mCardView.setCardBackgroundColor(ContextCompat.getColor(mContext, R.color.cardViewBackgroundSelected));
} else {
holder.mCardView.setCardBackgroundColor(ContextCompat.getColor(mContext, R.color.cardViewBackgroundNotSelected));
}

holder.update(mData.get(position));
}

public class RecyclerViewHolder extends BaseViewHolder {

private TextView txtTitle;

public RecyclerViewHolder(View itemView, ClickListener listener, Context context) {
super(itemView, listener, context);
txtTitle = (TextView) itemView.findViewById(R.id.txtCardTitle);
}

public void update(String text) {
txtTitle.setText(text);
}
}
}

همه چیز تا الان واضح به نظر میرسه . فقط باید دو تا color توی values->colors.xml ایجاد کنید که در واقعا رنگ cardview موقع select و deselect شدن هستش :

<color name="cardViewBackgroundSelected">#a6b0d8</color>
<color name="cardViewBackgroundNotSelected">#ffffff</color>

 

تمام تغییرات لازم انجام شد . بجر تغییرات اکتیویتی که در پس بعدی اون مورد رو هم توضیح میدم

 

 

 

پاسخ به سوال 
amirhossein1376  9 سال پیش
+4 0

بعد از کلی تایپ کردن یه بار ctrl+R زدم ( دستم خورد ) همه چی پاک شد!

------------------------------------------------------------------------------------

خوب الان وقتشه که یه منو بسازیم . همونی که قراره توی actionmode از اون استفاده بشه! من اسم منو رو میزارم menu_selected . پس یه منو به همین اسم توی values->menu ایجاد کنید و کدهای زیر رو داخلش کپی کنید : 

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/item_delete"
android:title="Delete"
app:showAsAction="always"/>
</menu>

حالا دیگه کدهای اکتیویتی رو یک جا کپی میکنم تا توی اکتیویتی مربوطه کپی کنید :

public class MainActivity extends AppCompatActivity implements ClickListener {

private List<String> data;
private RecyclerView recyclerView;
private RecyclerViewAdapter adapter;
private LinearLayoutManager manager;

private ActionModeCallback actionModeCallback = new ActionModeCallback();
private ActionMode actionMode;


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

data = new ArrayList<>();

for (int i = 0; i < 60; i++) {
data.add("Some Title Or Description " + i);
}

recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
adapter = new RecyclerViewAdapter(data, this, this);
manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(manager);

}

private void toggleSelection(int position) {
adapter.toggleSelection(position);
int count = adapter.getSelectedItemCount();

if (count == 0) {
actionMode.finish();
} else {
actionMode.setTitle(String.valueOf(count));
actionMode.invalidate();
}
}


@Override
public void onItemClicked(int position) {
if (actionMode != null) {
toggleSelection(position);
} else {
//Item Clicked!!! Do Some work
}

}

@Override
public boolean onItemLongClicked(int position) {
if (actionMode == null) {
actionMode = startSupportActionMode(actionModeCallback);
}

toggleSelection(position);
return true;
}

private class ActionModeCallback implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.menu_selected, menu);
return true;
}

@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}

@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.item_delete:
adapter.clearSelection();
actionMode.finish();
return true;
default:
return false;
}
}

@Override
public void onDestroyActionMode(ActionMode mode) {
adapter.clearSelection();
actionMode = null;
}
}

}

 

با این تغییرات پس اجرای اکتیویتی ActionMode قابل اجرا میشه و میشه دید که میشه چندتا آیتم رو انتخاب کرد : 

 

ظاهرا هیچ مشکلی نیست ولی یادتون باشه اگر قراره از custom toolbar استفاده کنید باید توی تم اکتیویتی مربوطه این خط رو قرار بدید : 

<item name="windowActionModeOverlay">true</item>

اگر بخواید رنگ ActionMode رو هم تغییر بدید توی values خط زیر رو قرار بدید : 

<item name="actionModeBackground">@color/colorPrimary</item> <!-- change to your own color-->

 

خوب کار تموم شد ! 

اسکرین نهایی : 

 

پاسخ به سوال 
amirhossein1376  9 سال پیش
+1 0

احتمالا توضیحات من زیاد خوب نبوده !

پروژه رو با گیت پیش بردم و میتونید تو گیت هاب ببینیدش و کامل تر استفاده بکنید

 

 https://github.com/amirhossein1376/RecyclerView-ActionMode

 

پاسخ به سوال 
Meysam_Apr  7 سال پیش
0 0

توضیحاتتون خیلیم خوبه فقط ی سوال چطور دکمه انتخاب همه رو اضافه میش کرد؟


پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .