带有 CustomAdapter 的 Fragment 中的多个 OnClickListeners

Multiple OnClickListeners in Fragment with CustomAdapter

问题: 我正在尝试通过浮动操作按钮将三个不同的 OnClickListeners 实施到回收站视图的每个项目中。三个 FAB 中的每一个都做一些不同的事情,所以他们需要不同的 OnClickListeners。我想我可以用我当前的适配器设置实例化一个,但我希望能够通过这样的方式访问片段中的所有三个:

   mRecyclerView2.addItemDecoration(itemDecoration2);
   mLayoutManager2 = new GridLayoutManager(mContext, 3);
   mRecyclerView2.setLayoutManager(mLayoutManager2);
   mAdapter2 = new photo_adapter2(mContext, arrayList2);
   mRecyclerView2.setAdapter(mAdapter2);

   mAdapter2.floatingActionButtonDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                 int position = mRecyclerView2.getChildAdapterPosition(v);
                 photo_item2 item = mAdapter2.getDataSet().get(position);
                 final String key = item.getMatchId();
            }
        });


   mAdapter2.floatingActionButtonView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = mRecyclerView2.getChildAdapterPosition(v);
                photo_item2 item = mAdapter2.getDataSet().get(position);
                final String key = item.getMatchId();
            }
        });


   mAdapter2.floatingActionButtonChat.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int position = mRecyclerView2.getChildAdapterPosition(v);
                photo_item2 item = mAdapter2.getDataSet().get(position);
                final String key = item.getMatchId();
            }
        });

移动到片段时出现以下错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.material.floatingactionbutton.FloatingActionButton.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        at com.example.firetest.Tabs.MatchProcess.MatchFragment.onCreateView

适配器:

public class photo_adapter2 extends RecyclerView.Adapter<photo_adapter2.ViewHolder> {

    ImageView imageView;
    FloatingActionButton floatingActionButtonDelete;
    FloatingActionButton floatingActionButtonChat;
    FloatingActionButton floatingActionButtonView;

    private Uri imageUri;
    private ArrayList<photo_item2> mDataSet;
    private Context mContext;
    private OnItemClickListener mListener;
    
    public ArrayList<photo_item2> getDataSet() {
        return mDataSet;
    }
    public void setDataSet(ArrayList<photo_item2> mDataSet) {
        this.mDataSet = mDataSet;
    }
    public ImageView getImageView() {
        return imageView;
    }
    public void setImageView(ImageView imageView) {
        this.imageView = imageView;
    }
    public Context getContext() {
        return mContext;
    }
    public void setContext(Context mContext) {
        this.mContext = mContext;
    }
    public Uri getImageUri() {
        return imageUri;
    }
    public void setImageUri(Uri imageUri) {
        this.imageUri = imageUri;
    }

    public interface OnItemClickListener {
        void onItemClick(int position);
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        mListener = listener;
    }

    public photo_adapter2(Context context, ArrayList<photo_item2> DataSet) {
        mDataSet = DataSet;
        mContext = context;
    }

    public ArrayList<photo_item2> DataSet() {
        return mDataSet;
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ImageView mImageView;
        public FloatingActionButton floatingActionButtonDelete;
        public FloatingActionButton floatingActionButtonView;
        public FloatingActionButton floatingActionButtonChat;
        public RelativeLayout mLinearLayout;
        private int adapterPositionOnCLick;

        public ViewHolder(View v, final OnItemClickListener listener) {
            super(v);

            mImageView = (ImageView) v.findViewById(R.id.tv);

            floatingActionButtonDelete = (FloatingActionButton) v.findViewById(R.id.floatingActionButtonDelete);
            floatingActionButtonChat = (FloatingActionButton) v.findViewById(R.id.floatingActionButtonChat);
            floatingActionButtonView = (FloatingActionButton) v.findViewById(R.id.floatingActionButtonView);

            floatingActionButtonDelete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        adapterPositionOnCLick = getAdapterPosition();
                        if (adapterPositionOnCLick != RecyclerView.NO_POSITION) ;
                        listener.onItemClick(adapterPositionOnCLick);
                    }
                }
            });
            floatingActionButtonChat.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        adapterPositionOnCLick = getAdapterPosition();
                        if (adapterPositionOnCLick != RecyclerView.NO_POSITION) ;
                        listener.onItemClick(adapterPositionOnCLick);
                    }
                }
            });

            floatingActionButtonView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        adapterPositionOnCLick = getAdapterPosition();
                        if (adapterPositionOnCLick != RecyclerView.NO_POSITION) ;
                        listener.onItemClick(adapterPositionOnCLick);
                    }
                }
            });
            mLinearLayout = (RelativeLayout) v.findViewById(R.id.ll);
        }
        public ImageView getImageView() {
            return mImageView;
        }
        public void setImageView(ImageView mImageView) {
            this.mImageView = mImageView;
        }
    }
    @Override
    public photo_adapter2.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(mContext).inflate(R.layout.photo_custom_view_card, parent, false);
        ViewHolder vh = new ViewHolder(v, (OnItemClickListener) mListener);
        return vh;

    }
    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        final photo_item2 photo_item = mDataSet.get(position);
    }
    @Override
    public int getItemCount() {
        return mDataSet.size();
    }
}

我该如何创建三个这样的 onClickListeners?我应该如何修改我当前的片段和适配器设置来实现这一点?如果还有什么我应该添加到我的 post.

中,请告诉我

检查您的 XML 文件,其中创建了所有三个浮动操作按钮,确保您已创建所有这些按钮,并使用您从视图访问的相应名称。 NullPointerException 告诉您您的浮动操作按钮之一指向了尚不存在的内容。

我认为,您可以创建一个 interface onFabClickListener 来将 FloatingActionButton 上的原始 onClick 事件发送到您的 ActivityFragment.如果三个 FloatingActionButtons 只是与 RecyclerView 交互的方式,那么我猜你甚至不需要处理 onItemClick()(或一个处理整体行的点击)。

界面 onFabClickListener.java 可能如下所示:

// is supposed to handle every fab click of every viewholder
public interface OnFabClickListener {
    // view to know which fab was click and position to know the position
    // of viewholder that was clicked
    void onFabClick(View view, int position);
}

那么你的 Adapter class 可能看起来像这样:

public class photo_adapter2 extends RecyclerView.Adapter<photo_adapter2.ViewHolder> {

// you all other variable declarations
private ArrayList<photo_item2> mDataSet;
private Context mContext;
private OnFabClickListener mListener;

// your all other required methods definition

public void setOnFabClickListener(OnFabClickListener listener) {
    mListener = listener;
}

public ArrayList<photo_item2> getDataSet() {
    return mDataSet;
}

public void setDataSet(ArrayList<photo_item2> mDataSet) {
    this.mDataSet = mDataSet;
}

public photo_adapter2(Context context) {
    mContext = context;
}

@NonNull
@Override
public photo_adapter2.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(mContext).inflate(R.layout.photo_custom_view_card, parent, false);
    return new ViewHolder(v, mListener);

}

@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
    final photo_item2 photo_item = mDataSet.get(position);
    // do you stuff here
}

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


public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private OnFabClickListener listener;

    public ViewHolder(View v, final OnFabClickListener listener) {
        super(v);
        // your all other view initialization

        //setting our listener object
        this.listener = listener;

        // your all other views declaration
        FloatingActionButton floatingActionButtonDelete = v.findViewById(R.id.floatingActionButtonDelete);
        FloatingActionButton floatingActionButtonChat = v.findViewById(R.id.floatingActionButtonChat);
        FloatingActionButton floatingActionButtonView = v.findViewById(R.id.floatingActionButtonView);

        // setting onclicklisteners on them
        // our view holder class is gonna handle all of the onclick
        floatingActionButtonDelete.setOnClickListener(this);
        floatingActionButtonChat.setOnClickListener(this);
        floatingActionButtonView.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        // if the view is a floating action button and listener is not equal to null
        if (view instanceof FloatingActionButton && listener != null) {
            if (getAdapterPosition() != RecyclerView.NO_POSITION) {
                // for every on click listened here we will dispatch it to our activity or fragment which
                // is required to respond to those events
                listener.onFabClick(view, getAdapterPosition());
            }
        }
    }

    // your all other methods definition
}
}  

那么现在实现我们的自定义 onFabClickListener 的示例 MainActivity 将接收最初由我们的 photo_adapter2 class 处理和调度的适当的 onclick 事件,可能如下所示:

public class MainActivity extends AppCompatActivity implements OnFabClickListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    // declare and initialize the recyclerview
    RecyclerView rcView = ......
    // declare and initialize the requiredadapter
    photo_adapter2 adapter = .....
    // set the data using setDataSet() or you can skip this if you
    // already passed the dataset in the constructor
    adapter.setDataSet(yourDataSet);
    // set this class as the onFabClickListener(you forgot this one I guess)
    adapter.setOnFabClickListener(this);
    // set the adapter to the recyclerview
    rcView.setAdapter(adapter);
}


@Override
public void onFabClick(View view, int position) {
    int id = view.getId();
    switch (id) {
        case R.id.floatingActionButtonDelete:
            // you can now do your stuff here
            break;
        case R.id.floatingActionButtonChat:
            // for eg get the item associated with the viewholder of whose fab was clicked
            photo_item2 item = mAdapter2.getDataSet().get(position);
            break;
        case R.id.floatingActionButtonView:
            break;
    }
}
}  

注:
根据Material Design Specifications,单屏不建议使用多个FloatingActionButton(Activity/Fragment)。它表示用户执行的最重要的单个频繁操作。相反,我认为您应该切换到 MaterialButton,如果您使用 Fab 只是为了获得这种圆形外观,则需要立即切换。您可以在 styles.xml 文件中指定 materialButtonStyle 属性以获得圆形外观。