show code block

2017年7月20日 星期四

Android方法(RecyclerView) — RecyclerView外接到activity點擊事件

前言:

最近比較有空,把之前做的一些東西整理一下。
其中還有一個RecyclerView的外接點擊事件,就是模擬ListView的setOnItemClickListener的方法。
RecyclerView的點擊事件通常都直接寫在onBindViewHolder內,直接對holder內的元件寫onClick。
但如果要拉到activity內寫就要額外製作了。
我把上一部的DEMO拿來做示範。
DEMO下載: https://drive.google.com/open?id=0Byk75IYx-dKXNXEzdzlzUEwzc3M

今日實作
 


 簡單步驟:

一、在RecyclerView內holder這個方法必須implements View.OnClickListener 寫onClick方法
二、寫interface方法,在方法內寫onClickHello 抓取view和position
三、在RecyclerView內宣告剛剛寫的interface這方法
四、寫setListener讓activity使用回調
五、在holder內註冊你元件的監聽事件
完成!
這樣就可以在activity內調用adapter的點擊事件了

一、在RecyclerViewAdapter內holder這個方法必須implements View.OnClickListener 寫onClick方法
 //1、implements View.OnClickListener 寫onClick方法
    class dataHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private ImageView imageView;
        private TextView textView;

        public dataHolder(View itemView) {
            super(itemView);
            imageView = (ImageView) itemView.findViewById(R.id.image_view);
            textView = (TextView) itemView.findViewById(R.id.text_view);
            //5、註冊監聽事件
            itemView.setOnClickListener(this);
            textView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (clickListener != null)
                clickListener.onClickHello(view, getAdapterPosition());
        }
    }

 
二、寫interface方法,在方法內寫onClickHello 抓取view和position

寫在RecyclerViewAdapter內。
 //2、寫interface 方法 在方法內寫onClcikHello 抓取view和position
    public interface onItemClickListener {
        void onClickHello(View view, int position);
    }
 

三、在RecyclerView內宣告剛剛寫的interface這方法
    private onItemClickListener clickListener;//3、在元件這註冊
 

四、寫setListener讓activity使用回調
 //4、寫setListener讓activity使用回調
    public void setOnItemClickListener(onItemClickListener listener) {
        this.clickListener = listener;
    }
 


五、在holder內註冊你元件的監聽事件
 //1、implements View.OnClickListener 寫onClick方法
    class dataHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private ImageView imageView;
        private TextView textView;

        public dataHolder(View itemView) {
            super(itemView);
            imageView = (ImageView) itemView.findViewById(R.id.image_view);
            textView = (TextView) itemView.findViewById(R.id.text_view);
            //5、註冊監聽事件
            itemView.setOnClickListener(this);
            textView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (clickListener != null)
                clickListener.onClickHello(view, getAdapterPosition());
        }
    }
 

Adapter完成後,讓我們把畫面轉到MainActivity.java內,開始使用它吧!
 dataAdapter.setOnItemClickListener(new DataAdapter.onItemClickListener() {
            @Override
            public void onClickHello(View view, final int position) {
                Toast.makeText(MainActivity.this, "點擊事件position = " + position, Toast.LENGTH_SHORT).show();
            }
        });
 




完整Adapter程式碼:

 

class DataAdapter extends RecyclerView.Adapter<DataAdapter.dataHolder> implements Filterable {

    private final static String TAG = DataAdapter.class.getSimpleName();

    //元件
    private Context context;
    private ArrayList<Data> datalists;//是會變動的陣列,用來顯示正個recyclerView的資料
    private ArrayList<Data> filterDatas;//固定陣列,用來和filter比對用的。
    private MyFliter myFliter;//讓mainActivity能使用adapter呼叫篩選功能
    private onItemClickListener clickListener;//3、在元件這註冊

    //2、寫interface 方法 在方法內寫onClcikHello 抓取view和position
    public interface onItemClickListener {
        void onClickHello(View view, int position);
    }

    //4、寫setListener讓activity使用回調
    public void setOnItemClickListener(onItemClickListener listener) {
        this.clickListener = listener;
    }

    //建構子
    public DataAdapter(Context context) {
        this.context = context;
    }

    //implements Filterable的必定覆寫的方法,讓我們在activity內能呼叫他
    @Override
    public Filter getFilter() {
        if (myFliter == null) {
            myFliter = new MyFliter();
        }
        return myFliter;
    }

    //1、implements View.OnClickListener 寫onClick方法
    class dataHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private ImageView imageView;
        private TextView textView;

        public dataHolder(View itemView) {
            super(itemView);
            imageView = (ImageView) itemView.findViewById(R.id.image_view);
            textView = (TextView) itemView.findViewById(R.id.text_view);
            //5、註冊監聽事件
            itemView.setOnClickListener(this);
            textView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (clickListener != null)
                clickListener.onClickHello(view, getAdapterPosition());
        }
    }

    //讓我們在activity內能讀取或更新adapter內data的資料
    public void setData(ArrayList<Data> datalists) {
        this.datalists = datalists;
        filterDatas = datalists;
        notifyDataSetChanged();
    }

    @Override
    public DataAdapter.dataHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
        dataHolder dh = new dataHolder(view);
        return dh;
    }

    @Override
    public void onBindViewHolder(DataAdapter.dataHolder holder, int position) {
        Glide.with(context)
                .load(datalists.get(position).getImageUrl())
                .placeholder(R.drawable.default_image)
                .into(holder.imageView);

        if (!TextUtils.isEmpty(datalists.get(position).getTitle()))
            holder.textView.setText(datalists.get(position).getTitle());
        else
            holder.textView.setText("暫無資料");
    }

    @Override
    public int getItemCount() {
        return datalists == null ? 0 : datalists.size();
    }

    //實作自己的篩選Filter
    class MyFliter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence filterContent) {
            ArrayList<Data> filterData = new ArrayList<>();
            //先判斷filterContent是不是null才進入
            if (filterContent != null && filterContent.toString().trim().length() > 0) {
                Log.d(TAG, "確認是否為空值。 filterData.size = " + filterData.size());
                //這回圈是在判斷你輸入的文字(filterContent)是否有在filterDatas陣列內有相關的文字,逐條搜尋。
                for (int i = 0; i < filterDatas.size(); i++) {
                    String content = filterDatas.get(i).getTitle();
                    Log.d(TAG, "確認是否進入for迴圈 content = " + content);
                    if (content.contains(String.valueOf(filterContent))) {
                        Log.d(TAG, "確認輸入文字是否相同。");
                        Data data = new Data();
                        data.setImageUrl(filterDatas.get(i).getImageUrl());
                        data.setTitle(filterDatas.get(i).getTitle());
                        filterData.add(data);
                    }
                }
            } else {
                filterData = filterDatas;
                Log.d(TAG, "確認什麼都沒打 filterDatas = datalists = " + filterData.size());

            }
            FilterResults filterResults = new FilterResults();
            filterResults.count = filterData.size();
            filterResults.values = filterData;
            Log.d(TAG, "final size = " + filterResults.count);
            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            datalists = (ArrayList<Data>) filterResults.values;
            if (filterResults.count > 0) {
                notifyDataSetChanged();
            } else {
                Data data = new Data();
                data.setTitle("沒有結果");
                datalists.add(data);
                notifyDataSetChanged();
            }
        }
    }
}


DEMO:

https://drive.google.com/open?id=0Byk75IYx-dKXQWo5ZF9IeDdlZFE

5 則留言:

  1. 請問:不要寫點擊事件,是要能點擊後開啟另一個activity,要怎麼寫呢???
    謝謝。

    回覆刪除
  2. 兩種做法
    一、寫點擊事件,然後再A actiity內調用,然後startActivity(...);開啟另外一個activity
    二、直接在RecyclerView Adapter內的onBindViewHolder直接對你的item做onClicklistener。
    在調用Adapter的時候要順便把Context這參數帶到Adapter內
    ex: MyAdapter ma = new MyAdapter(context);
    然後在onClickListner內使用 context.startActivity(...);

    回覆刪除
  3. 您好,
    請問如何在點擊時取得Item內容? 如, Item內有多個textView,點擊後目前可以取得position,但是被點的該列內容該如何取得呢?
    謝謝

    回覆刪除
    回覆
    1. 在上述的程式碼中 onClickHello 更改參數 帶入你要的data

      刪除
    2. public interface onItemClickListener {
      void onClickHello(View view, int position,data);
      }

      刪除

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...