仿人民日报客户端报纸版面,首先来看下人民日报app的效果图,Demo代码地址:https://github.com/wangguifa/paper

如图所示,进入报纸页面会显示报纸的缩略图,每篇文章是一个版块,当点击该文章时,文章所在区域会被阴影覆盖,模拟用户选中效果,松开手指会进入文章详情页,本篇文章我们主要来介绍这个阴影效果是如何实现的。
接口数据分析:

注:该数据通过抓包获取,只用作学习使用,本文中不公布接口,只使用其数据。

以2019年4月13日数据为例,data为包含8个报纸版面的数组,由于数据太长,这里我只展示了第一个报纸版面,后面7个版面折叠了,每个版面中又包含了一定数量的item数组,每个item为一篇文章,其中points字段展示的数据就是每篇文章的阴影区域的坐标,我们只需要将这些坐标首位顺次连接就能得到该阴影区域,下面来看代码实现。

首先要自定义一个阴影View,来显示用户点击后的阴影区域,代码如下:

package com.guifa.paper;import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.view.View;import java.util.List;/*** 阴影View*/
public class CoverView extends View {/*** 阴影View的坐标,首尾顺次连接即可得到该阴影区域*/private List<PointF> ps;/*** 文章ID,为了进入详情页获取该文章内容*/private String newsId;/*** 阴影View默认的透明度*/private int alpha = 0;public CoverView(Context context) {super(context);}public CoverView(Context context, List<PointF> ps, String newsId) {super(context);this.ps = ps;this.newsId = newsId;}@Override@SuppressLint("DrawAllocation")protected void onDraw(Canvas canvas) {super.onDraw(canvas);Path path = new Path();for (int i = 0; i < ps.size(); i++) {PointF p = ps.get(i);if (p == null) {continue;}if (i == 0) {// 设置阴影View的坐标起点path.moveTo(p.x, p.y);} else {// 依次连接各个坐标得到该阴影区域path.lineTo(p.x, p.y);}}path.close();Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);paint.setColor(Color.TRANSPARENT);paint.setAlpha(alpha);canvas.drawPath(path, paint);}public List<PointF> getPs() {return ps;}public String getNewsId() {return newsId;}public void setAlpha(int alpha) {this.alpha = alpha;}
}

在构造方法中我们接收了ps和newsId两个参数,ps是阴影View的各个点坐标,我们根据坐标来顺次连接即可得到该阴影区域,newId是文章id当我们点击文章进入文章详情页的时候需要时候,用此来获取文章详情。

package com.guifa.paper;import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.ProgressBar;import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;import java.util.ArrayList;
import java.util.List;public class PaperImageView extends FrameLayout {/*** 阴影View未被选中时的透明度*/private static final int ALPHA_DEFAULT = 0;/*** 阴影View被选中时的透明度*/private static final int ALPHA_CLICKED = 80;/*** 上下文*/private Context context;/*** 用户点击后的回调*/private CallBackAction callBack;/*** 加载进度条*/private ProgressBar progressBar;/*** 版面是否加载成功*/private boolean loadComplete;private CoverView selectView = null;private float lastX;public PaperImageView(Context context) {super(context);this.context = context;}public PaperImageView(Context context, AttributeSet attrs) {super(context, attrs);this.context = context;}/*** 加载报纸版面图*/public void loadingPaperImage(PaperImage image) {if (progressBar == null) {// 显示加载进度条showProgressBar();}Glide.with(this).load(image.getPage_pic()).into(new SimpleTarget<Drawable>() {@Overridepublic void onResourceReady(@NonNull Drawable resource, Transition<? super Drawable> transition) {// 加载报纸版面缩略图setBackgroundDrawable(resource);}});PaperImageView.this.removeAllViews();// 每版报纸的文章ListList<PaperImage.ItemsBean> items = image.getItems();for (int i = 0; i < items.size(); i++) {List<PointF> ps = new ArrayList<>();// 每篇文章的newsIdString newsId = items.get(i).getArticleid() + "";// 每篇文章的点阵("points":"1047,139;1047,7;538,7;538,139;538,238;1047,238")String points = items.get(i).getPoints();// 根据";"分割成单个坐标String[] split = points.split(";");for (String aSplit : split) {// 根据","分割成x、y坐标String[] s = aSplit.split(",");if (TextUtils.isEmpty(s[0]) || TextUtils.isEmpty(s[1])) {return;}// 将x、y坐标加入List<PointF>中ps.add(new PointF(Float.parseFloat(s[0]), Float.parseFloat(s[1])));}// 将文章的坐标和newsId传入CoverView,加载阴影ViewCoverView cImageView = new CoverView(context, ps, newsId);// addViewPaperImageView.this.addView(cImageView);}// 隐藏加载进度条hideProgressBar();loadComplete = true;}/*** 正在加载报纸版面时的加载进度条*/public void showProgressBar() {loadComplete = false;setBackgroundDrawable(null);PaperImageView.this.removeAllViews();progressBar = new ProgressBar(context);LayoutParams layout = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);layout.gravity = Gravity.CENTER;this.addView(progressBar, layout);}/*** 隐藏加载进度条*/public void hideProgressBar() {if (progressBar != null) {this.removeView(progressBar);}}/*** 用户点击事件** @param event* @return*/@SuppressLint("ClickableViewAccessibility")@Overridepublic boolean onTouchEvent(MotionEvent event) {if (!loadComplete) {return true;}switch (event.getAction()) {// 用户手指按下case MotionEvent.ACTION_DOWN:lastX = event.getX();PointF pointF = new PointF();pointF.set(lastX, event.getY());for (int i = 0; i < getChildCount(); i++) {CoverView cImageView = (CoverView) getChildAt(i);List<PointF> ps = cImageView.getPs();// 判断用户点击的坐标是否在该阴影View范围中,若在,则该阴影View显示阴影效果if (isPolygonContainPoint(pointF, ps)) {cImageView.setAlpha(ALPHA_CLICKED);cImageView.invalidate();selectView = cImageView;}}return true;// 用户手指抬起case MotionEvent.ACTION_UP:if (selectView != null) {selectView.setAlpha(ALPHA_DEFAULT);selectView.invalidate();if (Math.abs(lastX - event.getX()) < 12) {// 当用户手指移动距离的绝对值小于12时,认为它是点击事件,触发点击操作callBack.doAction(selectView.getNewsId());}selectView = null;}return true;// 用户取消操作case MotionEvent.ACTION_CANCEL:if (selectView != null) {selectView.setAlpha(ALPHA_DEFAULT);selectView.invalidate();selectView = null;}return true;}return super.onTouchEvent(event);}/*** 判断用户点击的坐标是否在阴影View范围中** @param pointF        用户点击的坐标* @param vertexPointFs 阴影View的坐标* @return true / false*/private boolean isPolygonContainPoint(PointF pointF, List<PointF> vertexPointFs) {int nCross = 0;for (int i = 0; i < vertexPointFs.size(); i++) {PointF p1 = vertexPointFs.get(i);PointF p2 = vertexPointFs.get((i + 1) % vertexPointFs.size());if (p1.y == p2.y) {continue;}if (pointF.y < Math.min(p1.y, p2.y)) {continue;}if (pointF.y >= Math.max(p1.y, p2.y)) {continue;}double x = (double) (pointF.y - p1.y) * (double) (p2.x - p1.x) / (double) (p2.y - p1.y) + p1.x;if (x > pointF.x) {nCross++;}}return (nCross % 2 == 1);}public void setCallBack(CallBackAction callBack) {this.callBack = callBack;}/*** 用户点击事件*/public interface CallBackAction {public void doAction(String newsId);}
}

在PaperImageView中,为其显示了版面图片,并在PaperImageView中循环加载CoverView,其中定义了一个CallBackAction接口,用来实现用户点击事件,当用户点击屏幕时,会判断用户点击的坐标位置在哪个CoverView的范围中,并让该CoverView改变透明度,模拟用户点击后的效果。
补充一下PaperImage代码:

package com.guifa.paper;import java.io.Serializable;
import java.util.List;public class PaperImage implements Serializable {/*** page_name : 要闻* page_num : 01* period_num : 2019-04-13* page_pic : https://rmrbcmsonline.peopleapp.com/upload/image/201904/201904130450041113.jpg?x-oss-process=image/resize,w_500* page_time : 1555270132* items : [{"points":"1047,139;1047,7;538,7;538,139;538,238;1047,238","title":"就任朝鲜国务委员会委员长","id":4052556,"articleid":3909557,"category_id":"115","authors":[],"news_timestamp":1555084800,"news_datetime":"2019-04-13","comment_count":0,"view_type":"paper_2","title_style":null,"description":null,"copyfrom":null,"news_link":null,"medias":null,"content":null},{},{},{},{},{},{},{}]*/private String page_name;private String page_num;private String period_num;private String page_pic;private int page_time;private List<ItemsBean> items;public String getPage_name() {return page_name;}public void setPage_name(String page_name) {this.page_name = page_name;}public String getPage_num() {return page_num;}public void setPage_num(String page_num) {this.page_num = page_num;}public String getPeriod_num() {return period_num;}public void setPeriod_num(String period_num) {this.period_num = period_num;}public String getPage_pic() {return page_pic;}public void setPage_pic(String page_pic) {this.page_pic = page_pic;}public int getPage_time() {return page_time;}public void setPage_time(int page_time) {this.page_time = page_time;}public List<ItemsBean> getItems() {return items;}public void setItems(List<ItemsBean> items) {this.items = items;}public static class ItemsBean {/*** points : 1047,139;1047,7;538,7;538,139;538,238;1047,238* title : 这是标题* id : 4052556* articleid : 3909557* category_id : 115* authors : []* news_timestamp : 1555084800* news_datetime : 2019-04-13* comment_count : 0* view_type : paper_2* title_style : null* description : null* copyfrom : null* news_link : null* medias : null* content : null*/private String points;private String title;private int id;private int articleid;private String category_id;private int news_timestamp;private String news_datetime;private int comment_count;private String view_type;public String getPoints() {return points;}public void setPoints(String points) {this.points = points;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getArticleid() {return articleid;}public void setArticleid(int articleid) {this.articleid = articleid;}public String getCategory_id() {return category_id;}public void setCategory_id(String category_id) {this.category_id = category_id;}public int getNews_timestamp() {return news_timestamp;}public void setNews_timestamp(int news_timestamp) {this.news_timestamp = news_timestamp;}public String getNews_datetime() {return news_datetime;}public void setNews_datetime(String news_datetime) {this.news_datetime = news_datetime;}public int getComment_count() {return comment_count;}public void setComment_count(int comment_count) {this.comment_count = comment_count;}public String getView_type() {return view_type;}public void setView_type(String view_type) {this.view_type = view_type;}}
}

最后在Activity中调用即可使用。
最终代码放在了GitHub:GitHub代码连接

仿人民日报客户端app报纸版面-Android相关推荐

  1. android简书app源码,仿简书APP源码(android)

    [实例简介] [实例截图] [核心代码] package com.yidou.wandou.example_33.ui; import android.content.Context; import ...

  2. Android自定义控件(四)仿网易客户端上拉加载更多

    上一篇仿得网页客户端的抽屉模式,这一篇继续,来写一写加载更多这个功能,通过自定义实现加载更多,先上图: 今天实现的就是如图中最下面的20条载入中...这个功能啦! 先来说一下思路: 1.在listvi ...

  3. android手机卫士、3D指南针、动画精选、仿bilibli客户端、身份证银行卡识别等源码...

    Android精选源码 android身份证.银行卡号扫描源码 android仿bilibili客户端 android一款3D 指南针 源码 android手机卫士app源码 android提醒应用, ...

  4. Android仿人人客户端(v5.7.1)——项目框架新做的调整描述(项目中基类java源码)...

    转载请标明出处:http://blog.csdn.net/android_ls/article/details/8909068 声明:没看过仿人人android客户端系列博文,前面的相关文章的朋友,请 ...

  5. Android仿人人客户端(v5.7.1)——网络模块处理的架构

    转载请标明出处:http://blog.csdn.net/android_ls/article/details/8732427 声明:仿人人项目,所用所有图片资源都来源于官方人人android客户端, ...

  6. 视频教程-仿淘宝客户端电商平台android初级速成-Android

    仿淘宝客户端电商平台android初级速成 北风网技术总监,在某大型电信设备公司担任架构师,主要从事电信领域的软件开发,经验丰富.对电信计费系统以及核心网软件系统有深入了解,对设计高可靠性,高扩展性的 ...

  7. 仿淘宝客户端电商平台android初级速成-张勇-专题视频课程

    仿淘宝客户端电商平台android初级速成-969人已学习 课程介绍         本教程从当下火热的商城项目入手,以讲师多年商城项目开发为核心,与北风网强强联手录制了<北风商城>And ...

  8. android 快传 源码_安卓APP仿茄子快传源码,Android项目源码类似茄子快传的快传项目包括服务端...

    适用范围:安卓APP仿茄子快传源码,Android项目源码类似茄子快传的快传项目包括服务端 演示地址:(以截图为准) 运行环境:Android+PC+web 其他说明: 本项目是一个基于安卓的类似茄子 ...

  9. Android 高仿74款APP

    Github搜索就有了 ---------------------------------------------------------------------------------------- ...

最新文章

  1. java 中线程的创建方式
  2. 读博难?DeepMind科学家Ruder提出读博/做研究的十条锦囊
  3. python有哪些软件包用来考察变量之间的相关性_Python计算数据相关系数(person、Kendall、spearman)...
  4. aurora IP中选择了小端支持,但小端体现在了什么地方呢?
  5. Android开发之Navigationdrawer导航抽屉功能的实现(源代码分享)
  6. 在C++中调用DLL中的函数
  7. 鼠标滚轮事件及解决滚轮事件多次触发问题
  8. 【剑指offer】面试题34:二叉树中和为某一值的路径
  9. mysql快速删除大表数据部分数据_mysql删除大表的部分数据
  10. 堆和栈的概念和区别?
  11. android 支付宝 地图,利用百度地图实现支付宝“到位”功能(地图模式)
  12. 【电商运营】试试这5种个性化营销方法,告别无效营销!
  13. @Insert的用法
  14. Java 小白 声明两个字符串:一个是“宋江,卢俊义,林冲,鲁智深,武松“;另一个是“及时雨,玉麒麟,豹子头,花和尚,行者“。以逗号为分隔符分割两个字符串,然后将人物绰号和名字拼接在一起并输出。
  15. 必要的先决条件安装失败_先决条件
  16. ASPNET 5 和 dnx commands
  17. Vue中使用纯CSS样式设计Table横向竖向滚动自定义个别列固定
  18. Windows10系统安装postgreSQL出错解决方法
  19. android wifi精灵,全能WiFi精灵
  20. 动态规划----最长子序列

热门文章

  1. 在线安装gem5和nvmain集成gem5
  2. NSString 遇到的坑
  3. 梦主博客教你网站的日常维护与推广
  4. 计算机网络的功能有哪些?
  5. 【C++ MFC开发】串口通信之多个编辑框输出
  6. 笨方法学习Python-习题36: 设计和调试
  7. 【精彩点评】吸取历史经验,构建坚实的比特币产业
  8. matlab 2012a mex设置,【mex成功但compile failed】:win7 64bit matlab R2012a mex问题
  9. 五分钟让你学会Python网络爬虫
  10. matlab handles结构体