相信小伙伴们都使用过分类订阅这个功能,像CSDN APP的分类订阅、还有各种新闻的个性化分类订阅,今天就来实现它!具体实现功能如下:

  • 长按进入可编辑模式(可编辑,并且分类框右边出现一个加(减)图标)
  • 编辑模式下可以通过点击分类进行订阅(或取消订阅),并且所有分类有抖动效果
  • 点击按钮退出编辑模式(也可以改成 退出当前页面 或者 其他事件)
  • 退出编辑模式的同时会保存当前订阅状态(下次进入页面时会显示上次修改后的状态)

温馨提示:如果ListView、GridView、RecycleView一个都不会的话建议先去学一个再来学习这个,会一个都行

话不多说先上效果图!

首先讲一下实现功能的大致思路:实现这个订阅功能主要是在于实现两个GridView(也可以用ListView或者Recycle,这里演示GridView)的点击功能,首先是长按进入编辑模式,利用长按监听对两个GridView设置右上角小图标以及抖动,然后是GridView的子项点击事件的监听,点击其中一个的时候,先把这个加到另外那个GridView里面去,然后移除点击的这个,最后点击保存是利用List的size()和for循环来保存当前GridView里面的所有项(算是奇淫技巧吧,只会这样了)!接下来详细讲:

XML布局

布局没啥讲的,就上下两个GridView,然后加了个按钮(简单到没话说)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="20sp"android:text="已订阅"android:textColor="@color/colorBlack"android:textSize="18sp" /><GridViewandroid:id="@+id/grid_top"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:numColumns="4" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="20sp"android:layout_weight="1"android:text="待订阅"android:textColor="@color/colorBlack"android:textSize="18sp" /><Buttonandroid:id="@+id/btn_ok"android:layout_width="wrap_content"android:layout_height="35dp"android:text="完成"android:textSize="12sp" /></LinearLayout><GridViewandroid:id="@+id/grid_bottom"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:numColumns="4" /></LinearLayout>
Item的布局(GridView的Item)

这里是一个LinearLayout里面放了一个TextView和一个ImageView然后把它们调整成ImageView重叠在TextView右上角

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="5dp"><TextViewandroid:id="@+id/txv_name"android:layout_width="80dp"android:layout_height="35dp"android:layout_marginTop="7dp"android:background="@drawable/txv_stroke"android:gravity="center"android:textSize="12sp" /><ImageViewandroid:id="@+id/imv_button"android:layout_width="20dp"android:layout_height="20dp"android:layout_marginLeft="-10dp"android:scaleType="centerCrop" /></LinearLayout></LinearLayout>

Adapter(GridView的适配器)

这里只放上来一个,我写了两个一样的Adapter(只有名字不一样),如果只用一个的话很麻烦,尤其是当更新数据的时候,会出现很多小BUG(亲测),当然你也可以去试试只用一个!

这里主要讲的是那个boolean值的作用,多生成一个构造方法,可以在Activity中通过实例化传入boolean值或者不传入实现是否显示右上角的小图标!(这里是当传入true时就会把小图标显示出来)

public class AdapterTopGrid extends BaseAdapter {Context mContext;List<BeanSubGrid> mList;boolean editMode;public AdapterTopGrid(Context mContext, List<BeanSubGrid> mList) {this.mContext = mContext;this.mList = mList;notifyDataSetChanged();}//boolean值是为了让右上角小图标显示出来public AdapterTopGrid(Context mContext, List<BeanSubGrid> mList, boolean editMode) {this.mContext = mContext;this.mList = mList;this.editMode = editMode;notifyDataSetChanged();}@Overridepublic int getCount() {return mList.size();}@Overridepublic Object getItem(int position) {return mList.get(position);}@Overridepublic long getItemId(int position) {return position;}class ViewHolder {private TextView mTxvName;private ImageView mImvButton;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder viewHolder = new ViewHolder();if (convertView == null) {convertView = LayoutInflater.from(mContext).inflate(R.layout.sub_grid_item, null);viewHolder.mTxvName = convertView.findViewById(R.id.txv_name);viewHolder.mImvButton = convertView.findViewById(R.id.imv_button);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.mTxvName.setText(mList.get(position).getName());//当Activity重新实例化Adapter并且传入true时,才让小图标显示出来if (editMode) {viewHolder.mImvButton.setImageResource(mList.get(position).getButton());}return convertView;}
}

JAVA后台

在这里首先是判断有没有存过数据,如果没有则使用默认数据(第一次进入软件),然后是GridView的长按事件,重新实例化Adpater,进入编辑模式,接着是GridView的子项点击事件,另一个加上点击的那个,然后移除当前点击的(这里注意先加后移除),然后是按钮的点击事件,利用for循环实现按一定规律以Key-Value的形式用SharePrefences保存数据,并且重新实例化Adapter,让GridView变回默认状态。

然后抖动功能的话,属于可选功能吧,这是做了,不想要的或者想要其他效果的可以选择删掉那几行代码!不会影响其他功能的实现!

public class SubActivity extends AppCompatActivity {private android.widget.GridView mGridTop;private android.widget.Button mBtnOk;private android.widget.GridView mGridBottom;List<BeanSubGrid> mListTop;List<BeanSubGrid> mListBottom;BeanSubGrid mBeanSubGrid;AdapterTopGrid mAdapterTopGrid;AdapterBottomGrid mAdapterBottomGrid;private boolean mEditMode;private String isEmpty;Context mContext;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.subscription);mContext = SubActivity.this;mGridTop = findViewById(R.id.grid_top);mBtnOk = findViewById(R.id.btn_ok);mGridBottom = findViewById(R.id.grid_bottom);//数据,此时判断是否存储过数据,没存储过数据就使用默认数据isEmpty = (String) PreferencesUtils.get(mContext, "gridTop0", "");if (isEmpty.isEmpty()) {setDataTop();} else {mListTop = new ArrayList<>();int size = (int) PreferencesUtils.get(mContext, "gridTop", 0);for (int i = 0; i < size; i++) {String topStr = (String) PreferencesUtils.get(mContext, "gridTop" + i, "");mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setButton(R.mipmap.img_cut);mBeanSubGrid.setName(topStr);mListTop.add(mBeanSubGrid);}}isEmpty = (String) PreferencesUtils.get(mContext, "gridBottom0", "");if (isEmpty.isEmpty()) {setDataBottom();} else {mListBottom = new ArrayList<>();int size = (int) PreferencesUtils.get(mContext, "gridBottom", 0);for (int i = 0; i < size; i++) {String bottomStr = (String) PreferencesUtils.get(mContext, "gridBottom" + i, "");mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setButton(R.mipmap.img_add);mBeanSubGrid.setName(bottomStr);mListBottom.add(mBeanSubGrid);}}//进入页面默认显示状态defaultGrid();//长按以后进入编辑模式mGridTop.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {//编辑模式longClickGrid();//改为return true,防止长按完还会触发点击事件return true;}});//两个GeidView的长按事件执行的是一样的mGridBottom.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {//编辑模式longClickGrid();//改为return true,防止长按完还会触发点击事件return true;}});//点击完成后退出编辑模式mBtnOk.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//把boolean值变为false,也就是退出了编辑模式,GridView的子项单击事件不能再执行mEditMode = false;//默认模式(不显示右上角图标)defaultGrid();//这里是停止抖动AnimationUtils.Translater(mGridTop, 0);AnimationUtils.Translater(mGridBottom, 0);PreferencesUtils.put(mContext, "gridTop", mListTop.size());for (int gridTop = 0; gridTop < mListTop.size(); gridTop++) {PreferencesUtils.put(mContext,"gridTop"+gridTop,mListTop.get(gridTop).getName());}PreferencesUtils.put(mContext, "gridBottom", mListBottom.size());for (int gridBottom = 0; gridBottom < mListBottom.size(); gridBottom++) {PreferencesUtils.put(mContext,"gridBottom"+gridBottom,mListBottom.get(gridBottom).getName());}}});//子项点击事件处理mGridTop.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {if (mEditMode) {//判断是否处于编辑模式//先把点击的加到下面mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setName(mListTop.get(position).getName());mBeanSubGrid.setButton(R.mipmap.img_add);mListBottom.add(mBeanSubGrid);//再把点击的移除mListTop.remove(position);//列表更新  由于两个GridView都发生了改变,所以需要对两个都进行更新mAdapterTopGrid.notifyDataSetChanged();mAdapterBottomGrid.notifyDataSetChanged();} else {ToastUtils.Toast(mContext, "请先长按进入编辑模式!");}}});mGridBottom.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {if (mEditMode) {//判断是否处于编辑模式//先把点击的加到上面mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setName(mListBottom.get(position).getName());mBeanSubGrid.setButton(R.mipmap.img_cut);mListTop.add(mBeanSubGrid);//再把点击的移除mListBottom.remove(position);//列表更新 由于两个GridView都发生了改变,所以需要对两个都进行更新mAdapterTopGrid.notifyDataSetChanged();mAdapterBottomGrid.notifyDataSetChanged();} else {ToastUtils.Toast(mContext, "请先长按进入编辑模式!");}}});}//编辑模式private void longClickGrid() {//boolean值变为true,GridView的子项单击事件可以执行了mEditMode = true;/*** 两个GridView的抖动,我是写在工具类里,这里可以复制出来直接用,根据方法的参数一样传入就行public static void Translater(View view, int repeatCount) {Animation animation = new TranslateAnimation(0, 1, 0, 1);animation.setDuration(200);animation.setRepeatCount(repeatCount);view.setAnimation(animation);}*/AnimationUtils.Translater(mGridTop, -1);AnimationUtils.Translater(mGridBottom, -1);mAdapterTopGrid = new AdapterTopGrid(mContext, mListTop, true);mGridTop.setAdapter(mAdapterTopGrid);mAdapterBottomGrid = new AdapterBottomGrid(mContext, mListBottom, true);mGridBottom.setAdapter(mAdapterBottomGrid);}//默认模式private void defaultGrid() {mAdapterTopGrid = new AdapterTopGrid(mContext, mListTop);mGridTop.setAdapter(mAdapterTopGrid);mAdapterBottomGrid = new AdapterBottomGrid(mContext, mListBottom);mGridBottom.setAdapter(mAdapterBottomGrid);}private void setDataTop() {//已订阅区域数据mListTop = new ArrayList<>();mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setName("军事");mBeanSubGrid.setButton(R.mipmap.img_cut);mListTop.add(mBeanSubGrid);mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setName("娱乐");mBeanSubGrid.setButton(R.mipmap.img_cut);mListTop.add(mBeanSubGrid);mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setName("JAVA");mBeanSubGrid.setButton(R.mipmap.img_add);mListBottom.add(mBeanSubGrid);}private void setDataBottom() {//待订阅区域数据mListBottom = new ArrayList<>();mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setName("Python");mBeanSubGrid.setButton(R.mipmap.img_add);mListBottom.add(mBeanSubGrid);mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setName("Android");mBeanSubGrid.setButton(R.mipmap.img_add);mListBottom.add(mBeanSubGrid);mBeanSubGrid = new BeanSubGrid();mBeanSubGrid.setName("IOS");mBeanSubGrid.setButton(R.mipmap.img_add);mListBottom.add(mBeanSubGrid);}
}

第二篇万字文章了,感谢阅读!有疑问或者更好的方法实现可以留言或者私信我,欢迎交流!

小白也能学会的Android应用分类订阅功能(新闻个性化分类订阅),学不会你打我!相关推荐

  1. 【深度学习】单标签多分类问题之新闻主题分类

    # -*- coding: utf-8 -*- """单标签多分类问题之新闻主题分类.ipynbAutomatically generated by Colaborato ...

  2. python爬虫爬取新闻实战01:小白如何迅速学会爬虫爬取上千条新闻

    爬虫爬取新闻实战01:小白如何迅速学会爬虫爬取千条新闻 文章目录 爬虫爬取新闻实战01:小白如何迅速学会爬虫爬取千条新闻 1.前言 2 .爬虫原理介绍 2.1.图片爬虫 2.2 文字爬虫 3.用八爪鱼 ...

  3. python 新闻标题分类_NLPCC2017(中文)新闻标题分类示例代码以及数据描述

    NLPCC 2017 新闻标题分类 代码运行环境 python2.7 (最好用anaconda2) tensorflow1.0.0 gpu版本或者cpu版本 建议操作系统:Linux Linux 上的 ...

  4. 基于朴素贝叶斯和LSTM的两种新闻文本分类方法

    新闻文本分类 文章目录 新闻文本分类 一.项目背景 二.数据处理与分析 三.基于机器学习的文本分类--朴素贝叶斯 1. 模型介绍 2. 代码结构 3. 结果分析 四.基于深度学习的文本分类--LSTM ...

  5. 数学之美 系列 12 - 余弦定理和新闻的分类

    数学之美 系列 12 - 余弦定理和新闻的分类 余弦定理和新闻的分类似乎是两件八杆子打不着的事,但是它们确有紧密的联系.具体说,新闻的分类很大程度上依靠余弦定理. Google 的新闻是自动分类和整理 ...

  6. 【新闻分类数据,新闻类别数据】

    Python新闻分类,新闻分类数据集 做新闻文本分类模型时,花了大量时间整理好的数据集(数据量达80多万),有需要的可以咨询留言,已经帮你们整理好了,财经.汽车.娱乐等16类80多万条新闻数据.已经保 ...

  7. 新闻本文分类-01赛题理解

    该文是连载文章,基于新闻文本分类赛题从而入门自然语言处理.主要从赛题理解.数据读取与数据分析.基于机器学习的文本分类.基于深度学习的文本分类这四部分来学习NLP. 一.赛题背景 本次新人赛是Dataw ...

  8. tracepro应用实例详解_建筑安装工程造价,高清PPT图文详解,小白也能学会的简单步骤...

    建筑安装工程造价,高清PPT图文详解,小白也能学会的简单流程 工程造价的直意就是工程的建造价格,是指进行某项工程建设所花费的全部费用.工程造价在工程中是很关键的存在,是工程能够取得的关键:对工程建设的 ...

  9. 一个Demo学会用Android兼容包新控件

    2019独角兽企业重金招聘Python工程师标准>>> 前言 伟大的Google为Android推出了一系列的兼容包,最新的就是Design Support Library了,这里我 ...

最新文章

  1. VUE中使用Echarts绘制地图迁移
  2. 21个UI设计必会的设计技巧
  3. Android JNI开发摘录(五)之对象引用处理
  4. Neo4j--第一章
  5. 什么是非集计模型_集计与非集计模型的关系
  6. 【Python】Python中的关键字
  7. git clone大文件EOF错误
  8. papervision3D官方文档CHM格式.
  9. 气象研究中的大气稳定性 Atmosphere stability
  10. python分位数回归模型_分位数回归及其Python源码导读
  11. 名词变复数,动词第三人称, 过去式 读音
  12. 微信小程序:Framework inner error FLOW_CREATE_NODE
  13. python 条形图 负值_使用python matplotlib获取正负值的堆积条形图
  14. 评论发表之屏蔽关键字
  15. Nat.Mach.Intell.|如何改进错义突变致病性预测?使用图注意神经网络试试
  16. 中国人工智能城市排名榜公布,北京、杭州、深圳居前
  17. 文科生参加计算机竞赛,文科生有保送的吗??
  18. python处理大型数据的csv
  19. 小程序报错 H.createEvent is not a function !已解决
  20. 大学生交友平台——项目启动篇

热门文章

  1. SAP Portfolio Analyzer信息比率(Information Ratio)
  2. (亚嵌)ARM920T的MMU与Cache之MMU
  3. 2022年商标注册时间以及申请流程,以蚌埠市为例
  4. PE工具装Windows10系统
  5. 赛效:怎么给照片换底色
  6. 某市出租车起步价10元,3公里后开始计价,30公里以内每公里是2元,超出30公里的部分每公里3元,定义公里数n计算最终因支付多少元
  7. 盘点这些年错过的互联网暴富机会,大部分人都后知后觉
  8. 2020/7/29 多远函数微分学——极值与最值
  9. Unity 打包出的iOS 游戏 图片质量(Alpha)下降的问题
  10. 怎么控制latex插图的位置_如何让Latex在指定位置插图?