c# 實現刷卡
Let's say a user of your site wants to edit a list item without opening the item and looking for editing options. If you can enable this functionality, it gives that user a good User Experience.
假設您網站的用戶想要在不打開列表項并尋找編輯選項的情況下編輯列表項。 如果您可以啟用此功能,它將為該用戶帶來良好的用戶體驗 。
Pocket, a bookmarking app owned by Mozilla, does something similar. You can share/archive/delete your saved articles directly from the list without opening the article. Then you can click the menu button in the top-right corner and select your edit option.
Pocket是Mozilla擁有的書簽應用程序,它執行類似的操作。 您可以直接從列表中共享/存檔/刪除保存的文章,而無需打開文章。 然后,您可以單擊右上角的菜單按鈕,然后選擇編輯選項。
So in this tutorial we'll try to code this one out.
因此,在本教程中,我們將嘗試對此進行編碼。
Here's what we want to achieve:
這是我們要實現的目標 :
首先讓我們創建一個普通的RecyclerView列表 (First let’s create a normal RecyclerView list)
RecyclerView is an advanced and flexible version of ListView and GridView. It's capable of holding large amounts of list data and has better performance than its predecessors.
RecyclerView是ListView和GridView的高級且靈活的版本。 它能夠保存大量列表數據,并且比以前的版本具有更好的性能。
As the name suggests, RecyclerView 'recycles' the items of our list once it's out of view on scrolling and re-populates them when they come back to view. So the list container has to maintain only a limited number of views and not the entire list.
顧名思義,RecyclerView在滾動時看不到列表時會“回收”列表中的項目,并在它們重新顯示時重新填充它們。 因此,列表容器只需要維護有限數量的視圖,而不必維護整個列表。
It's so flexible that the new ViewPager2 class, used to create swipe-able tabs, is written over RecyclerView.
它非常靈活,可以在RecyclerView上編寫用于創建可滑動標簽的新ViewPager2類。
創建一個POJO(普通的舊Java對象)以保存列表數據 (Create a POJO (Plain Old Java Object) to hold the list data)
public class RecyclerEntity {private String title;private boolean showMenu = false;private int image;public RecyclerEntity() {}public RecyclerEntity(String title, int image, boolean showMenu) {this.title = title;this.showMenu = showMenu;this.image = image;}public int getImage() {return image;}public void setImage(int image) {this.image = image;}//... all the getters and setters
}
Notice we have a showMenu member here which will handle the visibility of the menu for that list item in our RecyclerView.
請注意,這里有一個showMenu成員,它將處理RecyclerView中該列表項的菜單可見性。
創建一個RecyclerView適配器 (Create a RecyclerView Adapter)
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {List<RecyclerEntity> list;Context context;public RecyclerAdapter(Context context, List<RecyclerEntity> articlesList) {this.list = articlesList;this.context = context;}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View v;v= LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list, parent, false);return new MyViewHolder(v);}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {RecyclerEntity entity = list.get(position);if(holder instanceof MyViewHolder){((MyViewHolder)holder).title.setText(entity.getTitle());((MyViewHolder)holder).imageView.setImageDrawable(context.getResources().getDrawable(entity.getImage())); }}@Overridepublic int getItemCount() {return list.size();}public class MyViewHolder extends RecyclerView.ViewHolder {TextView title;ImageView imageView;ConstraintLayout container;public MyViewHolder(View itemView) {super(itemView);title = itemView.findViewById(R.id.title);imageView = itemView.findViewById(R.id.imageView);container = itemView.findViewById(R.id.container);}}
}
Usually we put our ViewHolder sub class (MyViewHolder) in the super class template. This lets us directly return our defined ViewHolder subclass object from the onCreateViewHolder() method. Then we don't have to cast it again and again in onBindViewHolder() method.
通常,我們將ViewHolder子類(MyViewHolder)放在超類模板中。 這使我們可以從onCreateViewHolder()方法直接返回定義的ViewHolder子類對象。 然后,我們不必在onBindViewHolder()方法中一次又一次地投射它。
But here we can't do that, and we'll learn why in a minute.
但是在這里我們無法做到這一點,我們將在一分鐘內了解原因。
在活動中初始化RecyclerView (Initialise the RecyclerView in the Activity)
public class MainActivity extends AppCompatActivity {RecyclerView recyclerView;List<RecyclerEntity> list;RecyclerAdapter adapter;@RequiresApi(api = Build.VERSION_CODES.M)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);recyclerView = findViewById(R.id.recyclerview);list = new ArrayList<>();list.add(new RecyclerEntity("This is the best title", R.drawable.one, false));list.add(new RecyclerEntity("This is the second-best title", R.drawable.two, false));//... rest of the list itemsadapter = new RecyclerAdapter(this, list);recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setAdapter(adapter);}
}
Now let's start making things a little more interesting.
現在,讓我們開始讓事情變得更加有趣。
為菜單創建布局資源 (Create a layout resource for the menu )
And initialise it in Recycler Adapter:
并在Recycler Adapter中對其進行初始化:
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {List<RecyclerEntity> list;Context context;private final int SHOW_MENU = 1;private final int HIDE_MENU = 2;public RecyclerAdapter(Context context, List<RecyclerEntity> articlesList) {this.list = articlesList;this.context = context;}@Overridepublic int getItemViewType(int position) {if(list.get(position).isShowMenu()){return SHOW_MENU;}else{return HIDE_MENU;}}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View v;if(viewType==SHOW_MENU){v= LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_menu, parent, false);return new MenuViewHolder(v);}else{v= LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list, parent, false);return new MyViewHolder(v);}}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {RecyclerEntity entity = list.get(position);if(holder instanceof MyViewHolder){//... same as above}if(holder instanceof MenuViewHolder){//Menu Actions}}@Overridepublic int getItemCount() {return list.size();}public class MyViewHolder extends RecyclerView.ViewHolder {//... same as above}//Our menu viewpublic class MenuViewHolder extends RecyclerView.ViewHolder{public MenuViewHolder(View view){super(view);}}
}
Now we have two ViewHolder sub-classes in our adapter, MyViewHolder (the actual list item) and MenuViewHolder. Both inherit the same class so we return the parent class RecyclerView.ViewHolder from onCreateViewHolder().
現在我們的適配器中有兩個ViewHolder子類,MyViewHolder(實際的列表項)和MenuViewHolder。 兩者都繼承同一個類,因此我們從返回父類RecyclerView.ViewHolder onCreateViewHolder()。
Our getItemViewType() method returns the int variable (viewType) which tells the kind of view we want to show in our RecyclerView for a particular position: that is, either MyViewHolder or MenuViewHolder.
我們的getItemViewType()方法返回int變量(viewType),該變量告訴我們要在RecyclerView中顯示的特定位置的視圖類型:MyViewHolder或MenuViewHolder。
This viewType variable is then used by onCreateViewHolder() which actually returns the respective ViewHolder object.
然后,onCreateViewHolder()使用此viewType變量,該變量實際上返回相應的ViewHolder對象。
在RecyclerAdapter中添加功能以顯示/隱藏菜單 (Add the functions to show/hide menu in RecyclerAdapter)
public void showMenu(int position) {for(int i=0; i<list.size(); i++){list.get(i).setShowMenu(false);}list.get(position).setShowMenu(true);notifyDataSetChanged();}public boolean isMenuShown() {for(int i=0; i<list.size(); i++){if(list.get(i).isShowMenu()){return true;}}return false;}public void closeMenu() {for(int i=0; i<list.size(); i++){list.get(i).setShowMenu(false);}notifyDataSetChanged();}
Note that there are many ways to handle this. But for simplicity's sake we're keeping a boolean value in our POJO to maintain the menu's visibility.
請注意,有很多方法可以解決此問題。 但是為了簡單起見,我們在POJO中保留一個布爾值以保持菜單的可見性。
After changing our data list, we call the notifyDataSetChanged() method to redraw the list.
更改數據列表后,我們調用notifyDataSetChanged()方法重繪該列表。
長按RecyclerAdapter中的列表項顯示菜單 (Show the menu on long press of our list item in RecyclerAdapter)
@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {RecyclerEntity entity = list.get(position);if(holder instanceof MyViewHolder){((MyViewHolder)holder).title.setText(entity.getTitle());((MyViewHolder)holder).imageView.setImageDrawable(context.getResources().getDrawable(entity.getImage()));((MyViewHolder)holder).container.setOnLongClickListener(new View.OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {showMenu(position);return true;}});}if(holder instanceof MenuViewHolder){//Set Menu Actions like://((MenuViewHolder)holder).edit.setOnClickListener(null);}}
Again, setting events on our views can also be done in various ways.
同樣,也可以通過各種方式在我們的視圖上設置事件。
In our example, we have three actions in our menu. You can write your logic to handle those actions in the second if statement like shown in the comments.
在我們的示例中,菜單中包含三個操作。 您可以在第二條if語句中編寫邏輯來處理這些動作,如注釋中所示。
滑動顯示菜單 (Show the menu on swipe )
To do this, we add a touch helper in our MainActivity.java:
為此,我們在MainActivity.java中添加了一個觸摸助手:
public class MainActivity extends AppCompatActivity {RecyclerView recyclerView;List<RecyclerEntity> list;RecyclerAdapter adapter;@RequiresApi(api = Build.VERSION_CODES.M)@Overrideprotected void onCreate(Bundle savedInstanceState) {//... same as above adapter = new RecyclerAdapter(this, list);recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setAdapter(adapter);ItemTouchHelper.SimpleCallback touchHelperCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {private final ColorDrawable background = new ColorDrawable(getResources().getColor(R.color.background));@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {return false;}@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {adapter.showMenu(viewHolder.getAdapterPosition());}@Overridepublic void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);View itemView = viewHolder.itemView;if (dX > 0) {background.setBounds(itemView.getLeft(), itemView.getTop(), itemView.getLeft() + ((int) dX), itemView.getBottom());} else if (dX < 0) {background.setBounds(itemView.getRight() + ((int) dX), itemView.getTop(), itemView.getRight(), itemView.getBottom());} else {background.setBounds(0, 0, 0, 0);}background.draw(c);}};ItemTouchHelper itemTouchHelper = new ItemTouchHelper(touchHelperCallback);itemTouchHelper.attachToRecyclerView(recyclerView);}
We call the showMenu() function inside our adapter when a list item is swiped.
刷列表項時,我們在適配器內部調用showMenu()函數。
The onChildDraw() function draws the background while we swipe. Otherwise there'll be a white background while swiping and our menu layout will show up with a pop.
滑動時,onChildDraw()函數繪制背景。 否則,在滑動時會出現白色背景,并且菜單布局會彈出。
隱藏菜單 (Hiding the menu)
There are three ways to hide our menu.
隱藏菜單的方法有三種。
- Hiding the menu when another row is swiped: 滑動另一行時隱藏菜單:
This case is already handled in showMenu() method in our Adapter. Before showing the menu for any row, we first call setShowMenu(false) for all the rows to hide the menu.
這種情況已經在我們適配器的showMenu()方法中處理過。 在顯示任何行的菜單之前,我們首先為所有行調用setShowMenu(false)以隱藏菜單。
2. ?Hiding the menu when the back button is pressed (in our Activity):
2.當按下后退按鈕時隱藏菜單(在我們的活動中):
@Overridepublic void onBackPressed() {if (adapter.isMenuShown()) {adapter.closeMenu();} else {super.onBackPressed();}}
3. ?Hiding the menu when a user scrolls the list:
3.當用戶滾動列表時隱藏菜單:
recyclerView.setOnScrollChangeListener(new View.OnScrollChangeListener() {@Overridepublic void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {adapter.closeMenu();}});
Though pocket only has a long-press action to show the menu, in this example we've added swipe to show the menu for added functionality. You can hide your menu item on swipe right/left again, but I think it might confuse the user.
盡管Pocket只有長按才能顯示菜單,但在此示例中,我們添加了滑動以顯示菜單以增加功能。 您可以再次向右/向左滑動隱藏菜單項,但我認為這可能會使用戶感到困惑。
結語 (Wrapping up)
If your app has a very large dataset to show in a RecyclerView, this type of UX might not be the way to go. In that case you should have a bulk-edit sort of functionality.
如果您的應用程序有很大的數據集要顯示在RecyclerView中,則可能無法采用這種類型的UX。 在這種情況下,您應該具有大量編輯功能。
Also if your edit options are more than what you can adjust in a RecyclerView row but you still want to show some quick actions, you can show a Bottomsheet dialog on long press of your item and it can have all your edit options. The Google Drive android app does exactly the same thing. ?
同樣,如果您的編輯選項超出了您在RecyclerView行中可以調整的范圍,但是您仍想顯示一些快速操作,則可以在長按該項目時顯示“底部工作表”對話框,并且可以擁有所有的編輯選項。 Google Drive Android應用程序執行的操作完全相同。
If you want to implement a simple swipe to delete function, the code for that can be found here on Github.
如果您想實現簡單的滑動刪除功能,可以在Github上找到相關代碼。
You can also check the source code for this project on Github.
您也可以在Github上檢查該項目的源代碼 。
Visit 22Boxes.com for more Mobile & Web development resources.
訪問22Boxes.com,以獲取更多移動和Web開發資源。
翻譯自: https://www.freecodecamp.org/news/how-to-implement-swipe-for-options-in-recyclerview/
c# 實現刷卡