组合控件——升级版翻页——下拉刷新布局SwipeRefreshLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 注意SwipeRefreshLayout要使用全路径 -->
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/srl_dynamic"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 注意RecyclerView要使用全路径 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_dynamic"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>
===================================================================================================
xml布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp"> <!-- 注意SwipeRefreshLayout要使用全路径 --> <androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/srl_dynamic" android:layout_width="match_parent" android:layout_height="wrap_content"> <!-- 注意RecyclerView要使用全路径 --> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_dynamic" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#aaaaff" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </LinearLayout>
主代码:
package com.example.myapplication; import android.annotation.SuppressLint; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.View; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener; import com.example.myapplication.adapter.LinearDynamicAdapter; import com.example.myapplication.bean.NewsInfo; import com.example.myapplication.widget.RecyclerExtras.OnItemClickListener; import com.example.myapplication.widget.RecyclerExtras.OnItemDeleteClickListener; import com.example.myapplication.widget.RecyclerExtras.OnItemLongClickListener; import com.example.myapplication.widget.SpacesDecoration; import java.util.List; import java.util.Random; @SuppressLint("DefaultLocale") public class MainActivity extends AppCompatActivity implements OnRefreshListener, OnItemClickListener, OnItemLongClickListener, OnItemDeleteClickListener { private SwipeRefreshLayout srl_dynamic; // 声明一个下拉刷新布局对象 private RecyclerView rv_dynamic; // 声明一个循环视图对象 private LinearDynamicAdapter mAdapter; // 声明一个线性适配器对象 private List<NewsInfo> mPublicList = NewsInfo.getDefaultList(); // 当前的公众号信息列表 private List<NewsInfo> mOriginList = NewsInfo.getDefaultList(); // 原始的公众号信息列表 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 从布局文件中获取名叫srl_dynamic的下拉刷新布局 srl_dynamic = findViewById(R.id.srl_dynamic); srl_dynamic.setOnRefreshListener(this); // 设置下拉布局的下拉刷新监听器 // 设置下拉刷新布局的进度圆圈颜色 srl_dynamic.setColorSchemeResources(R.color.red, R.color.orange, R.color.green, R.color.blue); initRecyclerDynamic(); // 初始化动态线性布局的循环视图 } // 初始化动态线性布局的循环视图 private void initRecyclerDynamic() { // 从布局文件中获取名叫rv_dynamic的循环视图 rv_dynamic = findViewById(R.id.rv_dynamic); // 创建一个垂直方向的线性布局管理器 LinearLayoutManager manager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false); rv_dynamic.setLayoutManager(manager); // 设置循环视图的布局管理器 // 构建一个公众号列表的线性适配器 mAdapter = new LinearDynamicAdapter(this, mPublicList); mAdapter.setOnItemClickListener(this); // 设置线性列表的点击监听器 mAdapter.setOnItemLongClickListener(this); // 设置线性列表的长按监听器 mAdapter.setOnItemDeleteClickListener(this); // 设置线性列表的删除按钮监听器 rv_dynamic.setAdapter(mAdapter); // 设置循环视图的线性适配器 rv_dynamic.setItemAnimator(new DefaultItemAnimator()); // 设置循环视图的动画效果 rv_dynamic.addItemDecoration(new SpacesDecoration(1)); // 设置循环视图的空白装饰 } // 一旦在下拉刷新布局内部往下拉动页面,就触发下拉监听器的onRefresh方法 public void onRefresh() { mHandler.postDelayed(mRefresh, 2000); // 模拟网络耗时,延迟若干秒后启动刷新任务 } private Handler mHandler = new Handler(Looper.myLooper()); // 声明一个处理器对象 // 定义一个刷新任务 private Runnable mRefresh = new Runnable() { @Override public void run() { srl_dynamic.setRefreshing(false); // 结束下拉刷新布局的刷新动作 int position = new Random().nextInt(mOriginList.size()-1); // 获取一个随机位置 NewsInfo old_item = mOriginList.get(position); NewsInfo new_item = new NewsInfo(old_item.pic_id, old_item.title, old_item.desc); mPublicList.add(0, new_item); // 在顶部添加一条公众号消息 mAdapter.notifyItemInserted(0); // 通知适配器列表在第一项插入数据 rv_dynamic.scrollToPosition(0); // 让循环视图滚动到第一项所在的位置 // 当循环视图的列表项已经占满整个屏幕时,再往顶部添加一条新记录, // 感觉屏幕没有发生变化,也没看到插入动画。 // 此时就要调用scrollToPosition(0)方法,表示滚动到第一条记录。 } }; // 一旦点击循环适配器的列表项,就触发点击监听器的onItemClick方法 public void onItemClick(View view, int position) { String desc = String.format("您点击了第%d项,标题是%s", position + 1, mPublicList.get(position).title); Toast.makeText(this, desc, Toast.LENGTH_SHORT).show(); } // 一旦长按循环适配器的列表项,就触发长按监听器的onItemLongClick方法 public void onItemLongClick(View view, int position) { NewsInfo item = mPublicList.get(position); item.isPressed = !item.isPressed; mPublicList.set(position, item); mAdapter.notifyItemChanged(position); // 通知适配器列表在第几项发生变更 } // 一旦点击循环适配器列表项的删除按钮,就触发删除监听器的onItemDeleteClick方法 public void onItemDeleteClick(View view, int position) { mPublicList.remove(position); mAdapter.notifyItemRemoved(position); // 通知适配器列表在第几项删除数据 } }
SpacesDecoration
package com.example.myapplication.widget; import android.graphics.Rect; import android.view.View; import androidx.recyclerview.widget.RecyclerView; public class SpacesDecoration extends RecyclerView.ItemDecoration { private int space; // 空白间隔 public SpacesDecoration(int space) { this.space = space; } @Override public void getItemOffsets(Rect outRect, View v, RecyclerView parent, RecyclerView.State state) { outRect.left = space; // 左边空白间隔 outRect.right = space; // 右边空白间隔 outRect.bottom = space; // 上方空白间隔 outRect.top = space; // 下方空白间隔 } }
RecyclerExtras
package com.example.myapplication.widget; import android.view.View; public class RecyclerExtras { // 定义一个循环视图列表项的点击监听器接口 public interface OnItemClickListener { void onItemClick(View view, int position); } // 定义一个循环视图列表项的长按监听器接口 public interface OnItemLongClickListener { void onItemLongClick(View view, int position); } // 定义一个循环视图列表项的删除监听器接口 public interface OnItemDeleteClickListener { void onItemDeleteClick(View view, int position); } }
NewsInfo
package com.example.myapplication.bean; import com.example.myapplication.R; import java.util.ArrayList; import java.util.List; public class NewsInfo { public int pic_id; // 图片的资源编号 public String title; // 标题 public String desc; // 描述 public boolean isPressed; // 是否按下 public int id; // 商品信息编号 private static int seq = 0; // 序号 public NewsInfo(int pic_id, String title, String desc) { this.pic_id = pic_id; this.title = title; this.desc = desc; this.isPressed = false; this.id = this.seq; this.seq++; } private static int[] newsImageArray = {R.drawable.public_01, R.drawable.public_02 , R.drawable.public_03, R.drawable.public_04, R.drawable.public_05}; private static String[] newsTitleArray = { "首都日报", "海峡时报", "东方周末", "参照消息", "挨踢杂志"}; private static String[] newsDescArray = { "北京冬奥精彩纷呈,中外健儿各显神通", "庆祝伟大统一,闽台两地合办中秋晚会", "日本新娘仰慕中土,纷纷跨海嫁往上海", "雅万高铁建成通车,中国标准再下一城", "Mate40大战iPhone12,两大豪机争上游"}; public static List<NewsInfo> getDefaultList() { List<NewsInfo> newsList = new ArrayList<NewsInfo>(); for (int i = 0; i < newsImageArray.length; i++) { newsList.add(new NewsInfo(newsImageArray[i], newsTitleArray[i], newsDescArray[i])); } return newsList; } private static int[] gridImageArray = {R.drawable.pic_01, R.drawable.pic_02, R.drawable.pic_03 , R.drawable.pic_04, R.drawable.pic_05, R.drawable.pic_06, R.drawable.pic_07 , R.drawable.pic_08, R.drawable.pic_09, R.drawable.pic_10}; private static String[] gridTitleArray = {"商场", "超市", "百货", "便利店", "地摊", "食杂店", "饭店", "餐厅", "会所", "菜市场"}; public static List<NewsInfo> getDefaultGrid() { List<NewsInfo> gridList = new ArrayList<NewsInfo>(); for (int i = 0; i < gridImageArray.length; i++) { gridList.add(new NewsInfo(gridImageArray[i], gridTitleArray[i], null)); } return gridList; } private static int[] stagImageArray = {R.drawable.skirt01, R.drawable.skirt02, R.drawable.skirt03 , R.drawable.skirt04, R.drawable.skirt05, R.drawable.skirt06, R.drawable.skirt07 , R.drawable.skirt08, R.drawable.skirt09, R.drawable.skirt10, R.drawable.skirt11 , R.drawable.skirt12, R.drawable.skirt13, R.drawable.skirt14, R.drawable.skirt15 , R.drawable.skirt16, R.drawable.skirt17, R.drawable.skirt18, R.drawable.skirt19 , R.drawable.skirt20, R.drawable.skirt21, R.drawable.skirt22, R.drawable.skirt23}; private static String[] stagTitleArray = {"促销价", "惊爆价", "跳楼价", "白菜价", "清仓价", "割肉价", "实惠价", "一口价", "满意价", "打折价", "腰斩价", "无人问津", "算了吧", "大声点", "嘘嘘", "嗯嗯", "呼呼", "呵呵", "哈哈", "嘿嘿", "嘻嘻", "嗷嗷", "喔喔"}; public static List<NewsInfo> getDefaultStag() { List<NewsInfo> stagList = new ArrayList<NewsInfo>(); for (int i = 0; i < stagImageArray.length; i++) { stagList.add(new NewsInfo(stagImageArray[i], stagTitleArray[i], null)); } return stagList; } private static int[] combineImageArray = {R.drawable.cainixihuan, R.drawable.dapaijiadao , R.drawable.trip_01, R.drawable.trip_02, R.drawable.trip_03, R.drawable.trip_04}; private static String[] combineTitleArray = { "猜你喜欢", "大牌驾到", "买哪个", "别想了", "先下单", "包你满意"}; public static List<NewsInfo> getDefaultCombine() { List<NewsInfo> combineList = new ArrayList<NewsInfo>(); for (int i = 0; i < combineImageArray.length; i++) { combineList.add(new NewsInfo(combineImageArray[i], combineTitleArray[i], null)); } return combineList; } private static int[] appiImageArray = {R.drawable.dian01, R.drawable.dian02, R.drawable.dian03 , R.drawable.dian04, R.drawable.dian05, R.drawable.dian06, R.drawable.dian07 , R.drawable.dian08, R.drawable.dian09, R.drawable.dian10, R.drawable.dian11 , R.drawable.dian12, R.drawable.dian13, R.drawable.dian14, R.drawable.dian15}; private static String[] appiTitleArray = {"双十一", "大聚惠", "爆款价", "就一次", "手慢无", "快点击", "付定金", "享特权", "包安装", "再返券", "白送你", "想得美", "干活去", "好好学", "才有钱"}; public static List<NewsInfo> getDefaultAppi() { List<NewsInfo> appiList = new ArrayList<NewsInfo>(); for (int i = 0; i < appiImageArray.length; i++) { appiList.add(new NewsInfo(appiImageArray[i], appiTitleArray[i], null)); } return appiList; } }
LinearDynamicAdapter
package com.example.myapplication.adapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.example.myapplication.R; import com.example.myapplication.bean.NewsInfo; import com.example.myapplication.widget.RecyclerExtras.OnItemClickListener; import com.example.myapplication.widget.RecyclerExtras.OnItemDeleteClickListener; import com.example.myapplication.widget.RecyclerExtras.OnItemLongClickListener; import java.util.List; public class LinearDynamicAdapter extends RecyclerView.Adapter<ViewHolder> implements View.OnClickListener, View.OnLongClickListener { private final static String TAG = "LinearDynamicAdapter"; private Context mContext; // 声明一个上下文对象 private List<NewsInfo> mPublicList; public LinearDynamicAdapter(Context context, List<NewsInfo> publicList) { mContext = context; mPublicList = publicList; } // 获取列表项的个数 public int getItemCount() { return mPublicList.size(); } // 创建列表项的视图持有者 public ViewHolder onCreateViewHolder(ViewGroup vg, int viewType) { // 根据布局文件item_linear.xml生成视图对象 View v = LayoutInflater.from(mContext).inflate(R.layout.item_linear, vg, false); return new ItemHolder(v); } // 根据列表项编号获取当前的位置序号 private int getPosition(int item_id) { int pos = 0; for (int i = 0; i < mPublicList.size(); i++) { if (mPublicList.get(i).id == item_id) { pos = i; break; } } return pos; } private int CLICK = 0; // 正常点击 private int DELETE = 1; // 点击了删除按钮 @Override public void onClick(View v) { int position = getPosition((int) v.getId() / 10); int type = (int) v.getId() % 10; if (type == CLICK) { // 正常点击,则触发点击监听器的onItemClick方法 if (mOnItemClickListener != null) { mOnItemClickListener.onItemClick(v, position); } } else if (type == DELETE) // 点击了删除按钮,则触发删除监听器的onItemDeleteClick方法 { if (mOnItemDeleteClickListener != null) { mOnItemDeleteClickListener.onItemDeleteClick(v, position); } } } @Override public boolean onLongClick(View v) { // 长按了列表项,则调用长按监听器的onItemLongClick方法 int position = getPosition((int) v.getId() / 10); if (mOnItemLongClickListener != null) { mOnItemLongClickListener.onItemLongClick(v, position); } return true; } // 绑定列表项的视图持有者 public void onBindViewHolder(ViewHolder vh, final int position) { NewsInfo item = mPublicList.get(position); ItemHolder holder = (ItemHolder) vh; holder.iv_pic.setImageResource(item.pic_id); holder.tv_title.setText(item.title); holder.tv_desc.setText(item.desc); holder.tv_delete.setVisibility((item.isPressed) ? View.VISIBLE : View.GONE); holder.tv_delete.setId(item.id * 10 + DELETE); holder.tv_delete.setOnClickListener(this); holder.ll_item.setId(item.id * 10 + CLICK); // 列表项的点击事件需要自己实现 holder.ll_item.setOnClickListener(this); // 列表项的长按事件需要自己实现 holder.ll_item.setOnLongClickListener(this); } // 获取列表项的类型 public int getItemViewType(int position) { return 0; } // 获取列表项的编号 public long getItemId(int position) { return position; } // 定义列表项的视图持有者 public class ItemHolder extends ViewHolder { public LinearLayout ll_item; // 声明列表项的线性布局 public ImageView iv_pic; // 声明列表项图标的图像视图 public TextView tv_title; // 声明列表项标题的文本视图 public TextView tv_desc; // 声明列表项描述的文本视图 public TextView tv_delete; // 声明列表项删除按钮的文本视图 public ItemHolder(View v) { super(v); ll_item = v.findViewById(R.id.ll_item); iv_pic = v.findViewById(R.id.iv_pic); tv_title = v.findViewById(R.id.tv_title); tv_desc = v.findViewById(R.id.tv_desc); tv_delete = v.findViewById(R.id.tv_delete); } } // 声明列表项的点击监听器对象 private OnItemClickListener mOnItemClickListener; public void setOnItemClickListener(OnItemClickListener listener) { this.mOnItemClickListener = listener; } // 声明列表项的长按监听器对象 private OnItemLongClickListener mOnItemLongClickListener; public void setOnItemLongClickListener(OnItemLongClickListener listener) { this.mOnItemLongClickListener = listener; } // 声明列表项的删除监听器对象 private OnItemDeleteClickListener mOnItemDeleteClickListener; public void setOnItemDeleteClickListener(OnItemDeleteClickListener listener) { this.mOnItemDeleteClickListener = listener; } }