CateyesLin / recycler-view-item-click

Sample for RecyclerView with OnItemClickListener

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

由於在 RecyclerView 內,不像之前的 ListView 有 setOnItemClickListener 可以用,而需要 Item Click 功能的需求很高。

這邊我就放一下我目前在用的寫法,但是請注意這僅是適用在我大部分的情境,你情況不同的話可能會遇到一些限制。 例如:你想要在 RecyclerView 中間插個廣告。這時候就請自己變形了。

先輕鬆一點,看個 OnItemClickListener,會傳 View 過來就是為了利用 id 可以知道是點到哪一個元件。如果一個 Row 上有不同的動作就可以善加利用。

public abstract class OnItemClickListener<T> {

    public abstract void onClick(int index, View source, T data);

    public final static OnItemClickListener DUMMY = new OnItemClickListener<Object>() {
        @Override
        public void onClick(int index, View source, Object data) {
        }
    };
}

最關鍵的是 ClickableRecyclerViewAdapter 定義共用的功能,並且利用泛型規定好資料型別,方便在 OnItemViewClick 取出來使用。

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

    OnItemClickListener itemClickListener = OnItemClickListener.DUMMY;

    //定義在 ids.xml 內,避免被人手殘弄到重複。
    public final int DATA_INDEX = R.id.tag_row_data;
    public final int POSITION_INDEX = R.id.tag_row_position;

    final View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //利用泛型進行 cast,方便在接的時候直接取用不用再轉一次。
            itemClickListener.onClick((Integer) v.getTag(POSITION_INDEX), v, (T) v.getTag(DATA_INDEX));
        }
    };
    //預先準備好空的 List,讓 getItemCount 不會 NullPointer
    protected List<T> data = Collections.emptyList();

    //用範型限定傳入的型別,加上 @NonNull 警告不要傳 null 進來。
    public ClickableRecyclerViewAdapter setData(@NonNull List<T> data) {
        this.data = data;
        notifyDataSetChanged();
        return this;
    }

    //定義類似 ListView 的 Adapter 使用的 getItem,方便在 onBindViewHolder 使用。
    public T getItem(int position) {
        return data.get(position);
    }

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

    public ClickableRecyclerViewAdapter setOnItemClickListener(OnItemClickListener<T> listener) {
        this.itemClickListener = null == listener ? OnItemClickListener.DUMMY : listener;
        return this;
    }

    //在 Bind 時只要呼叫這個功能就可以在某個 View 加上 Click 的接收。
    protected void enableClickOnView(int position, View view, T data) {
        view.setTag(POSITION_INDEX, position);
        view.setTag(DATA_INDEX, data);
        view.setOnClickListener(clickListener);
    }
}

既然定義好了就只要單純的跟平常使用 RecyclerView 一樣,針對要啟用點擊的 View 去呼叫 enableClickOnView

public class UserRecyclerViewAdapter extends ClickableRecyclerViewAdapter<User, UserRecyclerViewAdapter.ViewHolder> {

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        final View row = inflater.inflate(ViewHolder.LAYOUT_ID, parent, false);
        return new ViewHolder(row);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        final User user = getItem(position);
        holder.rowNumber.setText("" + position);
        holder.name.setText(user.name);
        holder.age.setText("" + user.age);
        holder.job.setText(user.jobTitle);
        holder.gender.setText(user.gender.strResId);

        //啟用點整列
        enableClickOnView(position, holder.itemView, user);

        //啟用點旁邊的編輯鈕
        enableClickOnView(position, holder.editButton, user);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        //此 ViewHolder 對應的 Layout
        public final static int LAYOUT_ID = R.layout.row_user;

        public final TextView rowNumber;

        public final TextView name;

        public final TextView age;

        public final TextView gender;

        public final TextView job;

        public final View editButton;

        public ViewHolder(View itemView) {
            super(itemView);

            rowNumber = (TextView) itemView.findViewById(R.id.row_number);
            name = (TextView) itemView.findViewById(R.id.name);
            age = (TextView) itemView.findViewById(R.id.age);
            gender = (TextView) itemView.findViewById(R.id.gender);
            job = (TextView) itemView.findViewById(R.id.job);
            editButton = itemView.findViewById(R.id.edit);
        }
    }
}

用起來就跟 ListView 很像,只是變成是在 Adapter 去做 setOnItemClickListener。利用 id 去分辨點到哪一個 View 就知道要做什麼處理。

public class MainActivity extends AppCompatActivity {

    //DataSet
    private final List<User> users = new ArrayList<>();

    UserRecyclerViewAdapter adapter = new UserRecyclerViewAdapter();
    RecyclerView list;

    protected Toast toast;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        prepareData();
        setupView();
    }

    private void prepareData() {
        users.add(new User(1, "John", "CEO", 23, MALE));
        users.add(new User(2, "Jack", "PM", 45, MALE));
        users.add(new User(3, "Mary", "UI", 21, FEMALE));
        users.add(new User(6, "Bob", "RD", 27, MALE));
        users.add(new User(9, "Alice", "RD", 22, FEMALE));
        users.add(new User(20, "Oak", "RD", 28, MALE));
        users.add(new User(34, "Lora", "PM", 27, FEMALE));
        users.add(new User(35, "Alec", "RD", 22, MALE));
        users.add(new User(39, "Patricia", "RD", 26, FEMALE));
        users.add(new User(41, "Valkry", "CTO", 40, FEMALE));
        users.add(new User(43, "Mike", "RD", 36, MALE));
    }

    private void setupView() {
        list = (RecyclerView) findViewById(R.id.list);
        list.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        list.setAdapter(adapter);
        adapter.setData(users);
        adapter.setOnItemClickListener(new OnItemClickListener<User>() {
            @Override
            public void onClick(int index, View source, User data) {
                switch (source.getId()) {
                    case R.id.edit:
                        toast("Edit " + data.name);
                        break;
                    default:
                        toast("View " + data.name);
                }
            }
        });
    }

    protected void toast(String text) {
        if(null != toast) {
            toast.cancel();
        }
        toast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
        toast.show();
    }
}

User 就…沒什麼好說的。 public class User {

//直接綁定 String Resource ID,作多國語言比較方便。
public enum Gender {
    MALE(R.string.male),
    FEMALE(R.string.female);

    public final int strResId;

    Gender(int strResId) {
        this.strResId = strResId;
    }
}

public final int id;

public final String name;

public final String jobTitle;

public final int age;

public final Gender gender;

public User(int id, String name, String jobTitle, int age, Gender gender) {
    this.id = id;
    this.name = name;
    this.jobTitle = jobTitle;
    this.age = age;
    this.gender = gender;
}

}

About

Sample for RecyclerView with OnItemClickListener


Languages

Language:Java 100.0%