【Android】适配器与外部事件的交互
三三要成为安卓糕手
引入:在上一篇文章中我们完成了新闻展示页面多布局案例的展示,感悟颇多,本篇文章,继续去开发一些新的功能
一:关闭广告
所有的view都可以和我们的用户做交互,循环视图中也给我们提供了相应的点击监听器
这是对整体做点击监听——缺点就是无法对内部单个控件进行监听
1:需求
点击关闭广告的字样后,广告关闭
思路:我们要找到广告对应的ViewHolder,在内部去找控件,进行监听,并处理关闭移除逻辑666
public class AdViewHolder extends RecyclerView.ViewHolder {private final ImageView ivPicture;private final View ivClose;public AdViewHolder(@NonNull View itemView) {super(itemView);ivPicture = itemView.findViewById(R.id.iv_picture);ivClose = itemView.findViewById(R.id.tv_close);ivClose.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {int layoutPosition = getLayoutPosition();articles.remove(layoutPosition);notifyItemRemoved(layoutPosition);}});}}
isClose对应的关闭广告这个控件,设置监听器,这里我们的Holder已经和position关联起来,此时在AdViewHolder中可以直接通过getLayoutPosition方法获取对应行号,战斗爽!
找到后,在数据源中直接移除(Position和index的位置恰好是一一对应的bro,在刷新一下item就OK了,思路还是非常清晰的
二:设置点击图片后跳转
问题:我现在点击广告,想要做的是跳转到广告页,或者是某个新闻的页面怎么做
以一张图片的为例,点击整个item都会进行跳转,所以是针对整体而非某个照片,文字
1:创建跳转后的Activity
创建一个新的Activity作为跳转后的页面
public class ArticleDetailActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_article_detail);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});}
}
2:页面跳转思路
回想一下之前学过的页面跳转是怎么个事,好多地方都用到了。
提问:我们不是在ArticleMoreListActivity中进行跳转,而是在Adapter中进行页面跳转,Adapter又不是一个Activity,那怎么整?
解决思路:我们把ArticleMoreListActivity作为this参数,在适配器实例化的时候传参进去就OK了
这里我们在适配器类中提供构造方法进行参数接收,并创建成员变量,完成变量的初始化
activity.startActivity(new Intent(activity,ArticleDetailActivity.class); 这一句代码是关键
itemView
并不是指整个 item 中所包含的所有控件,而是指当前列表项(item)的根视图。可以理解成最外层视图容器,这个根视图容器内部包含了该 item 的所有子控件
public class MyViewHolder extends RecyclerView.ViewHolder {private final ImageView ivPicture;private final TextView tvTitle;private final TextView tvAuthor;public MyViewHolder(@NonNull View itemView) {super(itemView);ivPicture = itemView.findViewById(R.id.iv_picture);tvTitle = itemView.findViewById(R.id.tv_title);tvAuthor = itemView.findViewById(R.id.tv_author);itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {
// int layoutPosition = getLayoutPosition();
// Article article = articles.get(layoutPosition);activity.startActivity(new Intent(activity,ArticleDetailActivity.class));}});}}
3:接口回调思想——页面回调
提出问题:把activity往适配中传是一件不优雅的事情,一般我们不会再适配器中处理具体的业务逻辑,跳转页面啥的
解决关键:想办法把这个点击事件告诉外面的activity
直观一点也就是把左图的点击事件想办法告诉ArticleMoreListActivity
三:优雅写法
1:交互事件分析
- 单个多个图片,点击页面跳转,长按,出现弹窗,不感兴趣,
- 点击广告页面跳转
2:适配器中的工作
(1)定义接口
public interface ArticleItemCallBack{/*** 点击一张图片* @param position* @param article*/void onSimpleItemClick(int position , Article article);/*** 对两张图片的item做长按操作* @param position* @param article*/void OnLongClickItem2Click(int position , Article article);/*** 点击广告* @param position* @param article*/void onAdClick(int position , Article article);}
(2)设计构造方法和定义成员变量
private ArticleItemCallBack articleItemCallBack;
也可以单独选择去创建一个方法调用
public ArticleMoreAdapter(ArticleItemCallBack articleItemCallBack) {this.articleItemCallBack = articleItemCallBack;}
(3)Holder中事件监听设置
public MyViewHolder(@NonNull View itemView) {super(itemView);/*** 对单张图片的item进行事件监听*/itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {int layoutPosition = getLayoutPosition();Article article = articles.get(layoutPosition);articleItemCallBack.onSimpleItemClick(layoutPosition,article);}});}
效果:
public MyViewHolder2(@NonNull View itemView) {super(itemView);/*** 对两张图片的item进行点击监听*/itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {int layoutPosition = getLayoutPosition();Article article = articles.get(layoutPosition);articleItemCallBack.OnLongClickItem2Click(layoutPosition,article);}});}
public AdViewHolder(@NonNull View itemView) {super(itemView); /*** 对整个item容器进行监听*/itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {int layoutPosition = getLayoutPosition();Article article = articles.get(layoutPosition);articleItemCallBack.onAdClick(layoutPosition,article);}});}
3:Activity中的工作
(1)直接new CallBack 写法1
定义点击事件,看最上方的调用图就清楚流程了,这里的接口回调思想掌握住精髓了,真的感觉很奇妙
ArticleMoreAdapter adapter = new ArticleMoreAdapter(new ArticleMoreAdapter.ArticleItemCallBack() {@Overridepublic void onSimpleItemClick(int position, Article article) {Toast.makeText(ArticleMoreListActivity.this,"跳转到单张图片对应的新闻资讯",Toast.LENGTH_SHORT).show();startActivity(new Intent(ArticleMoreListActivity.this, ArticleDetailActivity.class));}@Overridepublic void OnLongClickItem2Click(int position, Article article) {Toast.makeText(ArticleMoreListActivity.this,"你长按了2张图片对应的布局",Toast.LENGTH_SHORT).show();}@Overridepublic void onAdClick(int position, Article article) {Toast.makeText(ArticleMoreListActivity.this,"准备前往广告详细页面",Toast.LENGTH_SHORT).show();}});
(2)this写法
等价写法,会显得代码更清爽;
类实现接口,类中重写方法,传参this即可666
public class ArticleMoreListActivity extends AppCompatActivity implements ArticleMoreAdapter.ArticleItemCallBack
//设置适配器ArticleMoreAdapter adapter = new ArticleMoreAdapter(this);
@Overridepublic void onSimpleItemClick(int position, Article article) {Toast.makeText(ArticleMoreListActivity.this,"跳转到单张图片对应的新闻资讯",Toast.LENGTH_SHORT).show();startActivity(new Intent(ArticleMoreListActivity.this, ArticleDetailActivity.class));}@Overridepublic void OnLongClickItem2Click(int position, Article article) {Toast.makeText(ArticleMoreListActivity.this,"你长按了2张图片对应的布局",Toast.LENGTH_SHORT).show();}@Overridepublic void onAdClick(int position, Article article) {Toast.makeText(ArticleMoreListActivity.this,"准备前往广告详细页面",Toast.LENGTH_SHORT).show();}