GridView長按進入多選模式的解決方案
先來個效果圖,但是我很奇怪為什麼上次我的gif會無法顯示希望這次可以顯示吧! 其實關於介面卡系列(GridView,ListView等)的多選模式已經有太多人寫過了。且基本思路都是一致的,需要兩個標誌位。一個是是否是多選模式,一個是是否被選中。但是大部分的文章都是告訴你需要寫個bean檔案,然後在List裡面指定泛型為bean檔案,但是這樣做有個問題,那就是你獲取到的資料在很多情況下無法和bean檔案匹配。這時候怎麼辦呢?好吧!廢話說得有點多了,來開始程式碼嗎! 首先是佈局檔案一個Activity的一個是每個item的
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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=".MainActivity"> <LinearLayout android:id="@+id/title_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:visibility="gone"> <TextView android:id="@+id/cancel" android:layout_width="0dp" android:layout_height="50dp" android:layout_weight="1" android:text="Cancel" android:textSize="30sp" android:background="#556699" android:textColor="@color/colorAccent" android:gravity="center"/> <TextView android:id="@+id/delete" android:layout_width="0dp" android:layout_height="50dp" android:layout_weight="1" android:text="Delete" android:textSize="30sp" android:background="#556699" android:textColor="@color/colorAccent" android:gravity="center"/> <TextView android:id="@+id/all_or_not" android:layout_width="0dp" android:layout_height="50dp" android:layout_weight="1" android:text="All" android:textSize="30sp" android:background="#556699" android:textColor="@color/colorAccent" android:gravity="center"/> </LinearLayout> <GridView android:id="@+id/grid_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:numColumns="3" android:horizontalSpacing="10dp" android:verticalSpacing="10dp" /> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/item_image" android:layout_width="100dp" android:layout_height="100dp" android:layout_centerInParent="true"/> <TextView android:id="@+id/item_name" android:layout_width="wrap_content" android:layout_height="30dp" android:layout_below="@id/item_image" android:layout_centerHorizontal="true" android:layout_marginTop="20dp" android:textSize="20sp" android:textColor="#669900"/> <RelativeLayout android:id="@+id/checkbox" android:layout_width="100dp" android:layout_height="150dp" android:background="#99000000" android:layout_centerInParent="true" android:visibility="gone"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:src="@drawable/photo_select"/> </RelativeLayout> </RelativeLayout>
接下來是PicBean檔案
public class PicBean { private int resId; private String name; public PicBean(int resId, String name) { this.resId = resId; this.name = name; } public int getResId() { return resId; } public void setResId(int resId) { this.resId = resId; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
這個不需要多加解釋了,然後是介面卡
public class ImageAdapter extends BaseAdapter {
private List<ImageBean> list;
private LayoutInflater inflater;
private OnShowItemClickListener onShowItemClickListener;
public ImageAdapter(Context context, List<ImageBean> list) {
this.list = list;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return list == null ? 0 : list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View layout;
ImageHolder holder;
if (convertView == null){
holder = new ImageHolder();
layout = inflater.inflate(R.layout.item_layout,null);
holder.itemImage = layout.findViewById(R.id.item_image);
holder.itemName = layout.findViewById(R.id.item_name);
holder.itemCheck = layout.findViewById(R.id.checkbox);
layout.setTag(holder);
}else {
layout = convertView;
holder = (ImageHolder) layout.getTag();
}
ImageBean bean = list.get(position);
holder.itemImage.setImageResource(bean.getResId());
holder.itemName.setText(bean.getName());
if (bean.isShow()){
if (bean.isCheck()){
bean.setCheck(true);
holder.itemCheck.setVisibility(View.VISIBLE);
}else {
bean.setCheck(false);
holder.itemCheck.setVisibility(View.GONE);
}
}else {
holder.itemCheck.setVisibility(View.GONE);
}
onShowItemClickListener.onShowItemClick(bean);
return layout;
}
class ImageHolder{
ImageView itemImage;
TextView itemName;
RelativeLayout itemCheck;
}
public interface OnShowItemClickListener{
void onShowItemClick(ImageBean bean);
}
//暴露給外部的回撥介面
public OnShowItemClickListener getOnShowItemClickListener() {
return onShowItemClickListener;
}
public void setOnShowItemClickListener(OnShowItemClickListener onShowItemClickListener) {
this.onShowItemClickListener = onShowItemClickListener;
}
}
這個介面卡就是一個很常見的寫法了 不用解釋了吧。如果你足夠細心的話你會發現在介面卡裡面有bean.isShow這句。你再返回去看看之前的PicBean檔案裡面根本就沒有這個方法啊!難道我貼錯了嗎?當然不是啦!注意看我在介面卡裡面的泛型是ImageBean了
public class ImageBean {
private int resId;
private String name;
//多選的標記
private boolean isShow;
//是否選中的標記
private boolean isCheck;
public ImageBean(int resId, String name, boolean isShow, boolean isCheck) {
this.resId = resId;
this.name = name;
this.isShow = isShow;
this.isCheck = isCheck;
}
public ImageBean() {
}
public ImageBean(int resId, String name) {
this.resId = resId;
this.name = name;
}
public int getResId() {
return resId;
}
public void setResId(int resId) {
this.resId = resId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isShow() {
return isShow;
}
public void setShow(boolean show) {
isShow = show;
}
public boolean isCheck() {
return isCheck;
}
public void setCheck(boolean check) {
isCheck = check;
}
}
也許你還會有疑問不要著急,來看看MainActivity裡面的程式碼處理
public class MainActivity extends AppCompatActivity implements ImageAdapter.OnShowItemClickListener{
private GridView gridView;
//實際的資料來源,可以想象成掃描系統得到的,這是為了模擬實際的資料來源與要用的bean檔案不匹配
private List<PicBean> picList;
//建立介面卡的時候需要傳入的資料來源
private List<ImageBean> imageList;
private ImageAdapter adapter;
//是否是多選模式的標記
private boolean isShow;
private LinearLayout titleLayout;
private TextView cancel, allOrNot, delete;
//用來記錄選中的item
private List<ImageBean> selectList;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageList = new ArrayList<>();
selectList = new ArrayList<>();
picList = new ArrayList<>();
initReallyData();
***for (int i = 0; i < picList.size(); i++) {
ImageBean bean = new ImageBean();
bean.setResId(picList.get(i).getResId());
bean.setName(picList.get(i).getName());
imageList.add(bean);
}** *
adapter = new ImageAdapter(this, imageList);
gridView = findViewById(R.id.grid_view);
gridView.setAdapter(adapter);
adapter.setOnShowItemClickListener(this);
gridView.setOnItemLongClickListener(onItemLongClickListener);
gridView.setOnItemClickListener(onItemClickListener);
}
private void initReallyData(){
for (int i = 0; i < 10; i++) {
PicBean beanOne = new PicBean(R.drawable.aaa, "1號佳麗" + (i + 1));
picList.add(beanOne);
PicBean beanTwo = new PicBean(R.drawable.asdf, "2號妹紙" + (i + 1));
picList.add(beanTwo);
PicBean beanThree = new PicBean(R.drawable.mei, "3號美眉" + (i + 1));
picList.add(beanThree);
PicBean beanFour = new PicBean(R.drawable.meimei, "4號御姐" + (i + 1));
picList.add(beanFour);
PicBean beanFive = new PicBean(R.drawable.mm, "5號蘿莉" + (i + 1));
picList.add(beanFive);
PicBean beanSix = new PicBean(R.drawable.we, "6號小萌" + (i + 1));
picList.add(beanSix);
}
}
@Override
public void onShowItemClick(ImageBean bean) {
if (bean.isCheck()&& !selectList.contains(bean)) {
selectList.add(bean);
if (selectList.size() == imageList.size()){
allOrNot.setText("NotAll");
}else {
allOrNot.setText("All");
}
Log.e(TAG, "onShowItemClick: selectList.size()============" + selectList.size() );
} else if (!bean.isCheck()&& selectList.contains(bean)) {
selectList.remove(bean);
if (selectList.size() != imageList.size()){
allOrNot.setText("All");
}else {
allOrNot.setText("NotAll");
}
}
}
private AdapterView.OnItemLongClickListener onItemLongClickListener = new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (isShow) {
return false;
} else {
isShow = true;
for (ImageBean bean : imageList) {
bean.setShow(true);
}
adapter.notifyDataSetChanged();
showView();
}
return true;
}
};
private AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (isShow) {
ImageBean bean = imageList.get(position);
if (bean.isCheck()) {
bean.setCheck(false);
} else {
bean.setCheck(true);
}
adapter.notifyDataSetChanged();
}else {
Toast.makeText(MainActivity.this,"you clicked the item",Toast.LENGTH_SHORT).show();
}
}
};
private void showView() {
titleLayout = findViewById(R.id.title_layout);
titleLayout.setVisibility(View.VISIBLE);
cancel = findViewById(R.id.cancel);
delete = findViewById(R.id.delete);
allOrNot = findViewById(R.id.all_or_not);
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectList.clear();
for (ImageBean bean : imageList) {
bean.setShow(false);
bean.setCheck(false);
}
isShow = false;
titleLayout.setVisibility(View.GONE);
}
});
allOrNot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (allOrNot.getText().toString().equals("All")) {
selectList.clear();
for (ImageBean bean : imageList) {
bean.setCheck(true);
selectList.add(bean);
allOrNot.setText("NotAll");
}
adapter.notifyDataSetChanged();
} else {
for (ImageBean bean : imageList) {
bean.setCheck(false);
selectList.clear();
allOrNot.setText("All");
}
adapter.notifyDataSetChanged();
}
}
});
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imageList.removeAll(selectList);
selectList.clear();
adapter.notifyDataSetChanged();
}
});
}
}
現在來解決最開始提出的問題,獲取的資料來源並不是我們想要的效果,怎麼辦呢?很顯然只能轉化成我們想要的樣子了啊。
for (int i = 0; i < picList.size(); i++) {
ImageBean bean = new ImageBean();
bean.setResId(picList.get(i).getResId());
bean.setName(picList.get(i).getName());
imageList.add(bean);
}
這段程式碼就是將資料來源轉化成我們想要的樣子的。這一點還是可以行得通的。雖然實際獲取到的資料來源並沒有任何一個bean檔案與之對應,但是它一定會包含某些資訊,比如說圖片則會有名字和路徑地址,音樂還會有時間作者等,這些資訊你都可以寫出對應的bean檔案來獲取。比如說
bean.setPath(picList.get(position).get("path")
當然了,實際的路徑不一定是"path",這個取決於你掃描檔案的時候存的什麼名字(就是資料持久化的技術,sharePreference或者是資料庫)這個我們不暫時深究。總之資料來源裡面一定有對應的資訊讓你取出來然後設定到對應的bean物件裡面,這樣你就可以新增到對應的列表了。這個迴圈的意思就是把所有獲取到資料都轉換成我們需要的資料。 然後剩下的一些就是基本的設定監聽了,需要注意的是退出多選模式的時候應該將標記清空。 還有就是多選模式下點選了All全選之後應該要變成取消全選(Not All)有些細節還可以再優化一下。這個你可以自己嘗試。最後還是附上原始碼 另外我還在網上看到另外一個實現多選的模式但是並沒有原始碼下載,也是資料來源和需要的資料不一致,到時候我也整理出來。