英文:
Multiple OnClickListeners in Fragment with CustomAdapter
问题
问题:我尝试通过浮动操作按钮将三个不同的OnClickListeners实现到每个项目的RecyclerView中。每个FAB都执行不同的操作,因此它们需要不同的OnClickListeners。我认为我可以使用当前的适配器设置实例化一个FAB,但我希望能够通过类似以下方式在片段中访问所有三个:
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
适配器:
public class photo_adapter2 extends RecyclerView.Adapter<photo_adapter2.ViewHolder> {
ImageView imageView;
FloatingActionButton floatingActionButtonDelete;
FloatingActionButton floatingActionButtonChat;
FloatingActionButton floatingActionButtonView;
// 其他成员变量和方法...
public photo_adapter2(Context context, ArrayList<photo_item2> DataSet) {
mDataSet = DataSet;
mContext = context;
}
// 其他方法...
}
如何创建三个像这样的onClickListeners?我应该如何修改当前的片段和适配器设置以实现这一目标?如果需要添加其他内容,请告诉我。
英文:
Problem: I am trying to implement three different OnClickListeners
via floating action buttons into every item of a recycler view. Each of the three FABs does something different so they need different OnClickListeners
. I think I am able to instantiate one with my current adapter setup, but I would like to be able to access all three in the fragment via something like this:
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();
}
});
I get the following error when I move to the fragment:
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
Adapter:
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();
}
}
How would I go about creating three onClickListeners
like this? How should I modify my current fragment and adapter set up to achieve that? Please let me know if there is anything else I should add to my post.
答案1
得分: 2
Sure, here's the translated code portion:
我认为,你可以创建一个 `interface` `onFabClickListener` 来分发原始的 `FloatingActionButton` 上的 `onClick` 事件给你的 `Activity` 或 `Fragment`。如果只有三个 `FloatingActionButtons` 是与 `RecyclerView` 的 **row** 进行交互的方式,那么我想你甚至不需要处理 `onItemClick()`(或者处理整个行的点击事件的方法)。
`onFabClickListener.java` 接口可能如下所示:
// 用于处理每个视图持有者的每个 fab 点击事件
public interface OnFabClickListener {
// view 用于知道哪个 fab 被点击,position 用于知道被点击的视图持有者的位置
void onFabClick(View view, int position);
}
然后你的 `Adapter` 类可能如下所示:
public class photo_adapter2 extends RecyclerView.Adapter<photo_adapter2.ViewHolder> {
// 你的所有其他变量声明
private ArrayList<photo_item2> mDataSet;
private Context mContext;
private OnFabClickListener mListener;
// 你的所有其他所需方法的定义
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);
// 在这里执行你的操作
}
@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);
// 你的所有其他视图初始化
// 设置我们的监听器对象
this.listener = listener;
// 你的所有其他视图声明
FloatingActionButton floatingActionButtonDelete = v.findViewById(R.id.floatingActionButtonDelete);
FloatingActionButton floatingActionButtonChat = v.findViewById(R.id.floatingActionButtonChat);
FloatingActionButton floatingActionButtonView = v.findViewById(R.id.floatingActionButtonView);
// 在它们上设置点击监听器
// 我们的视图持有者类将处理所有的点击事件
floatingActionButtonDelete.setOnClickListener(this);
floatingActionButtonChat.setOnClickListener(this);
floatingActionButtonView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
// 如果视图是一个浮动操作按钮并且监听器不为空
if (view instanceof FloatingActionButton && listener != null) {
if (getAdapterPosition() != RecyclerView.NO_POSITION) {
// 在这里处理每个点击事件,并最初将其分发到我们的活动或片段,这些活动或片段需要对这些事件作出响应
listener.onFabClick(view, getAdapterPosition());
}
}
}
// 你的所有其他方法的定义
}
}
然后,现在一个实现我们自定义 `onFabClickListener` 的示例 `MainActivity` 将接收到由我们的 `photo_adapter2` 类最初处理和分发的适当的点击事件,可能如下所示:
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);
// 声明并初始化 RecyclerView
RecyclerView rcView = ......
// 声明并初始化所需的适配器
photo_adapter2 adapter = .....
// 使用 setDataSet() 设置数据,或者如果你在构造函数中已经传递了数据集,可以跳过这一步
adapter.setDataSet(yourDataSet);
// 将这个类设置为 onFabClickListener(你可能忘记了这一步)
adapter.setOnFabClickListener(this);
// 将适配器设置给 RecyclerView
rcView.setAdapter(adapter);
}
@Override
public void onFabClick(View view, int position) {
int id = view.getId();
switch (id) {
case R.id.floatingActionButtonDelete:
// 现在你可以在这里执行你的操作
break;
case R.id.floatingActionButtonChat:
// 例如,获取与被点击的视图持有者相关联的项目
photo_item2 item = mAdapter2.getDataSet().get(position);
break;
case R.id.floatingActionButtonView:
break;
}
}
}
----------
**注意:** 根据 Material Design 规范,不建议在单个屏幕(`Activity`/`Fragment`)中使用多个 `FloatingActionButton`。它表示用户执行的最重要的单个频繁操作。我认为你应该切换到 `MaterialButton`,如果你仅仅是为了获得圆形外观而使用 `Fab`,你需要立即切换。你可以在 `styles.xml` 文件中指定 `materialButtonStyle` 属性以获得圆形外观。
<details>
<summary>英文:</summary>
I think, you can create an `interface` `onFabClickListener` to dispatch the original `onClick` event on the `FloatingActionButton` to your `Activity` or `Fragment`. If three `FloatingActionButtons` are only way to interact with the **row** of `RecyclerView`, then I guess you don't even need to handle `onItemClick()`(or one which handle onclick of row overall).
The interface `onFabClickListener.java` may look like this :
// 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);
}
Then your `Adapter` class may look like this :
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
}
}
Then now a sample `MainActivity` which implements our custom `onFabClickListener` will receive the appropriate onclick events handled and dispatched initially by our `photo_adapter2` class may look like this:
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;
}
}
}
----------
**Note:**
According to Material Design Specifications, it is not recommended to use more than one `FloatingActionButton` in the single screen(`Activity`/`Fragment`). It represents the most important single frequent action that is performed by the user. Instead, I think you should switch to `MaterialButton` and if you are using `Fab` just to get this circular look, you need to switch immediately. You can specify the `materialButtonStyle` attribute in your `styles.xml` file to get a circular look.
</details>
# 答案2
**得分**: 0
检查您的XML文件,其中创建了所有三个浮动操作按钮,请确保您已经创建了它们,并且名称与您从视图中访问的名称相对应。NullPointerException正在告诉您,其中一个浮动操作按钮指向尚不存在的内容。
<details>
<summary>英文:</summary>
Check your XML file where all three floating action buttons are created, make sure you have them all created, with the respective names that you accessing from the view. The NullPointerException is telling you that one of your floating action button's are pointed to something that doesn't yet exist.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论