如何实现一个循环显示超长图片的控件

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

某次被问到如何实现一个滚筒状的控件,就是可以将一张很长的图片沿着Y轴无限旋转,如下图所示:

大概就是这个意思,当时还不知道图片可以裁剪,想不出整个流程怎么搞,后来得知Bitmap有裁剪功能,才想到这个功能怎么实现,花了一下午时间整了一下有了成果。
这是这张长图:

然后旋转起来就是这个样子:

上面这个效果在实际运行过程中是非常流畅的,这张图片是按照每秒几帧截的,所以看起来一顿一顿的。

先来说说如何实现:

第一次:先按照屏幕的宽度截取这张长图的起始部分。
第二次:以偏移量开始,重复第一次的行为。

最后:当这张图片的结尾部分不足以支撑整个屏幕的宽度时,先截取这张图片的末尾部分,绘制。然后再以剩余的宽度截取图片的头部部分,绘制。依次进行,直至重新回到第一次。

/*** Created by shangbin on 2016/6/16.* Email: sahadev@foxmail.com*/
public class CylinderImageView extends View {//用于裁剪的原始图片资源private Bitmap mSourceBitmap = null;// 图片的高宽private int mBitmapHeight, mBitmapWidth;// 移动单位,每次移动多少个单位private final int mMoveUnit = 1;// 图片整体移动的偏移量private int xOffset = 0;private Bitmap mPointerA, mPointerB;// 用于持有两张拼接图片的引用,并释放原先的图片资源/*** 循环滚动标志位*/private boolean mRunningFlag;private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if (msg.what == 0) {invalidate();}}};public CylinderImageView(Context context, AttributeSet attrs) {super(context, attrs);initVideoView();}public CylinderImageView(Context context) {super(context);initVideoView();}public CylinderImageView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initVideoView();}private void initVideoView() {// 获取需要循环展示的图片的高宽mSourceBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.android_m_hero_1200);mBitmapHeight = mSourceBitmap.getHeight();mBitmapWidth = mSourceBitmap.getWidth();mRunningFlag = true;setFocusableInTouchMode(true);requestFocus();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// 简单设置一下控件的宽高,这里的高度以图片的高度为准setMeasuredDimension(widthMeasureSpec, MeasureSpec.makeMeasureSpec(mBitmapHeight, MeasureSpec.getMode(heightMeasureSpec)));}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);recycleTmpBitmap();final int left = getLeft();final int top = getTop();final int right = getRight();final int bottom = getBottom();// 计算图片的高度int height = bottom - top;// 第一张图的宽带int tempWidth = right - left;// 如果一张图片轮播完,则从头开始if (xOffset >= mBitmapWidth) {xOffset = 0;}// 重新计算截取的图的宽度tempWidth = xOffset + tempWidth >= mBitmapWidth ? mBitmapWidth - xOffset : tempWidth;mPointerA = Bitmap.createBitmap(mSourceBitmap, xOffset, 0, tempWidth, height > mBitmapHeight ? mBitmapHeight : height);Paint bitmapPaint = new Paint();// 绘制这张图canvas.drawBitmap(mPointerA, getMatrix(), bitmapPaint);// 如果最后的图片已经不足以填充整个屏幕,则截取图片的头部以连接上尾部,形成一个闭环if (tempWidth < right - left) {Rect dst = new Rect(tempWidth, 0, right, mBitmapHeight);mPointerB = Bitmap.createBitmap(mSourceBitmap, 0, 0, right - left - tempWidth,height > mBitmapHeight ? mBitmapHeight : height);// 将另一张图片绘制在这张图片的后半部分canvas.drawBitmap(mPointerB, null, dst, bitmapPaint);}// 累计图片的偏移量xOffset += mMoveUnit;//由handler的延迟发送产生绘制间隔if (mRunningFlag) {mHandler.sendEmptyMessageDelayed(0, 1);}}/*** 回收临时图像*/private void recycleTmpBitmap() {if (mPointerA != null) {mPointerA.recycle();mPointerA = null;}if (mPointerB != null) {mPointerB.recycle();mPointerB = null;}}/*** 恢复*/public void resume() {mRunningFlag = true;invalidate();}/*** 暂停*/public void pause() {mRunningFlag = false;}/*** 回收清理工作*/@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();pause();recycleTmpBitmap();mSourceBitmap.recycle();}
}

以上是CylinderImageView的实现代码。

其中有两个公开方法:
resume() 用于在Activity的onResume()中调用,以便恢复旋转。
pause() 用于在Activiyt的onPause()中调用,以便暂停旋转。

下面是使用示例:

public class MainActivity extends AppCompatActivity {private CylinderImageView cylinderImageView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);cylinderImageView = (CylinderImageView) findViewById(R.id.cylinderImageView);}@Overrideprotected void onResume() {super.onResume();cylinderImageView.resume();}@Overrideprotected void onPause() {super.onPause();cylinderImageView.pause();}
}

因为这个控件内部涉及大量的图片操作,所以大伙一定很关心内存的使用。我为此专门做了内存测试,结果内存占用非常小:

这张图是没有使用CylinderImageView时应用程序所占用的内存:17.9MB:

我这里所使用的示例图片的长宽是1200x353,也就是说它被加载到内存中所占用的内存大小是1200x353x4/1024/1024=1.61MB.

再加上在屏幕上所显示的Bitmap所占用的内存为:1080x353x4/1024/1024=1.45MB.(这里的1080是我的屏幕宽度,在屏幕上显示的图片占了整个屏幕的宽度,所以是1080)

因为内存回收并不是实时的,所以在内存使用最高峰时,所使用的内存=17.9+1.61+1.45x2=22.43.

实际的运行占用内存为:


上面两张图片的差距是图片内存回收的差值,但是这里的高峰内存值与我们计算的内存值有些差距,这是因为除了内存之外,我们还在XML布局文件中声明了控件以及加载控件也占用了一定的内存空间。

调用pause()方法的内存状况:

调用resume()方法的内存状况:


Activity销毁之后所占用的内存:

通过上面一系列图示说明这个控件将内存的消耗控制在了合理的范围之内,没有滥用内存。

最后,大功告成,不知道是否明白我说的呢?

相关Demo演示请参见:https://github.com/sahadev/CylinderImageView

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/479017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

斯坦福大学——人工智能本科4年课程清单

文 | Mihail Eric编 | 大数据文摘相信每个入行人工智能的老手&#xff0c;对自己过往的几年学习生涯都或多或少会有一些遗憾&#xff1a;如果我当年先从基本概念入手就好了&#xff0c;如果我当年把核心算法吃的更透一点就好了……最近&#xff0c;一位在行业内工作了几年的斯坦…

bert模型简介、transformers中bert模型源码阅读、分类任务实战和难点总结

bert模型简介、transformers中bert模型源码阅读、分类任务实战和难点总结&#xff1a;https://blog.csdn.net/HUSTHY/article/details/105882989 目录 一、bert模型简介 bert与训练的流程&#xff1a; bert模型的输入 二、huggingface的bert源码浅析 bert提取文本词向量 BertMo…

LeetCode 476. 数字的补数(移位 异或^)

1. 题目 给定一个正整数&#xff0c;输出它的补数。补数是对该数的二进制表示取反。 2. 解题 先求出该数的2进制有多少位然后分别每位与1进行异或操作 class Solution { public:int findComplement(int num) {int n 1, num_copy num;while(num_copy/2){n;num_copy / 2;}wh…

论文浅尝 - ICLR 2020 | 用于文本推理的神经模块网络

论文笔记整理&#xff1a;邓淑敏&#xff0c;浙江大学在读博士&#xff0c;研究方向为低资源条件下知识图谱自动化构建关键技术研究。论文链接&#xff1a;https://openreview.net/pdf?idSygWvAVFPr Demo链接: https://demo.allennlp.org/reading-comprehension 代码链接: htt…

全栈深度学习第3期: 怎样科学管理实验数据?

一起追剧鸭简介Berkeley全栈深度学习追剧计划是由夕小瑶的卖萌屋发起的优质公开课打卡项目&#xff0c;通过微信群为同期追剧的小伙伴提供交流平台。关于该计划的详请见这里。1. Berkeley深度学习追剧群目前已有1000小伙伴加入&#xff0c;公众号后台回复口令 深度学习追剧 入群…

论文浅尝 - ICLR2020 | 通过神经逻辑归纳学习有效地解释

论文笔记整理&#xff1a;朱渝珊&#xff0c;浙江大学直博生。研究方向&#xff1a;知识图谱&#xff0c;快速表示学习等。论文链接&#xff1a;https://arxiv.org/pdf/1910.02481.pdf本文是ICLR 2020的一篇关于知识图谱中关于复杂&#xff08;树状、组合&#xff09;规则可微学…

上海交大张拳石:神经网络的变量交互可解释性研究

文 | Qs.Zhang张拳石知乎可解释性研究一直有两副嘴脸&#xff0c;一副烈火烹油繁花似锦&#xff0c;一副如履薄冰零丁洋里叹零丁。在2018年我开始发知乎是为了“活着”——被刷榜为王的风气屡屡打击之后&#xff0c;一朝中稿&#xff0c;倒过一口气来&#xff0c;终于可以跟大家…

基于TensorFlow Serving的深度学习在线预估

一、前言 随着深度学习在图像、语言、广告点击率预估等各个领域不断发展&#xff0c;很多团队开始探索深度学习技术在业务层面的实践与应用。而在广告CTR预估方面&#xff0c;新模型也是层出不穷&#xff1a; Wide and Deep[^1]、DeepCross Network[^2]、DeepFM[^3]、xDeepFM[^…

python库Camelot从pdf抽取表格数据以及python库camelot安装及使用中的一些注意事项

一、python库camelot安装及使用中的一些注意事项 1&#xff09;camelot方法有两种解析模式&#xff1a;流解析&#xff08;stream&#xff09;、格子解析&#xff08;lattice&#xff09;&#xff0c;其中格子解析能够保留表格完整的样式&#xff0c;对于复杂表格来说要优于流…

LeetCode 561. 数组拆分 I

1. 题目 给定长度为 2n 的数组, 你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) &#xff0c;使得从1 到 n 的 min(ai, bi) 总和最大。 示例 1:输入: [1,4,3,2]输出: 4 解释: n 等于 2, 最大总和为 4 min(1, 2) min(3, 4).来源&#xff1a;力扣&…

论文浅尝 - 计算机工程 | 知识图谱可视化查询技术综述

本文转载自公众号&#xff1a;计算机工程。知识图谱可视化查询技术综述王鑫, 傅强, 王林, 徐大为, 王昊奋知识图谱作为符号主义发展的产物&#xff0c;是人工智能技术和系统中的重要组成部分&#xff0c;其在百科知识、生物信息、社交网络以及网络安全等领域被广泛运用。知识图…

用VS Code直接浏览GitHub代码 | 12.1K星

文 | 金磊(发自凹非寺)源 | 量子位“看GitHub代码”这件事上&#xff0c;还在网页上点点点&#xff1f;用开发工具看代码&#xff0c;不香吗&#xff1f;于是&#xff0c;它来了&#xff0c;它来了——可以直接用VS Code方式打开GitHub代码的工具。而且在短短几天时间里&#x…

APPKIT打造稳定、灵活、高效的运营配置平台

一、背景 美团App、大众点评App都是重运营的应用。对于App里运营资源、基础配置&#xff0c;需要根据城市、版本、平台、渠道等不同的维度进行运营管理。如何在版本快速迭代过程中&#xff0c;保持运营资源能够被高效、稳定和灵活地配置&#xff0c;是我们团队面临的重大考验。…

Android官方开发文档Training系列课程中文版:通知用户之大视图通知

原文地址&#xff1a;http://android.xsoftlab.net/training/notify-user/expanded.html#big-view 通知在通知栏中以两种风格呈现&#xff1a;正常视图与大视图。只有在通知展开的时候才会展示大视图。这只有在通知处于通知栏顶部时或者用户点击了通知时才会出现。 大视图于A…

论文浅尝-WSDM | Stepwise Reasoning for Multi-Relation QA

论文笔记整理&#xff1a;谭亦鸣&#xff0c;东南大学博士。来源&#xff1a;WSDM ’20链接&#xff1a;https://dl.acm.org/doi/pdf/10.1145/3336191.33718121.介绍知识图谱问答旨在利用知识图谱的结构化信息回答以自然语言提出的问题。当面对多关系问题时&#xff0c;现有基于…

从零搭建基于知识图谱的问答系统(以医疗行业为例)

清华大学人工智能研究院院长张钹院士2020年发表署名文章&#xff0c;首次全面阐述第三代人工智能的理念&#xff0c;提出第三代人工智能的发展路径是融合第一代的知识驱动和第二代的数据驱动的人工智能。基于知识图谱的推理&#xff0c;恰恰体现了第三代人工智能的特点。知识图…

Android官方开发文档Training系列课程中文版:通知用户之在通知中显示进度

原文地址&#xff1a;http://android.xsoftlab.net/training/notify-user/display-progress.html#FixedProgress 通知中包含了一个进度指示器&#xff0c;用来向用户展示一项正在进行中的工作状态。如果你可以确保任务会花费多长时间&#xff0c;并且可以在任何时候得知它完成…

LeetCode 109. 有序链表转换二叉搜索树(快慢指针+递归)

1. 题目 给定一个单链表&#xff0c;其中的元素按升序排序&#xff0c;将其转换为高度平衡的二叉搜索树。 本题中&#xff0c;一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链…

beeshell —— 开源的 React Native 组件库

背景 beeshell 是一个 React Native 应用的基础组件库&#xff0c;基于 0.53.3 版本&#xff0c;提供一整套开箱即用的高质量组件&#xff0c;包含 JavaScript&#xff08;以下简称 JS&#xff09;组件和复合组件&#xff08;包含 Native 代码&#xff09;&#xff0c;涉及前端…

论文浅尝 - ACL2020 | 用于链接预测的开放知识图谱嵌入

本文转载自公众号&#xff1a;PaperWeekly。 作者&#xff1a;舒意恒&#xff0c;南京大学硕士&#xff0c;研究方向&#xff1a;知识图谱。当前大量的知识图谱都是通过文本直接构建的。由于当前的知识图谱构建方法的局限性&#xff0c;其中难免包含对同一实体或关系…