利用Android属性动画实现Banner的原理与实践
事实上在Android刚推出属性动画的时候。就想利用它来设计一个Banner控件,一直没什么时间尝试。
在当时看我们应用中的Banner,使用计时器来控制自己主动播放,设置一个非常大的数,利用余数原理来实现ViewPager循环。在进行内存分析的时候。看似不起眼的Banner却是一个消耗内存的大户。相信非常多App的Banner都是计时器加ViewPager的方式实现的。
近期时间比較宽裕,能够做一些研究性的工作,因此打算尝试使用属性动画实现Banner。眼下不过尝试了一下怎样实现,暂还未将其做成一个控件,最后的演示样例代码也是如此。不过实现原理的一个演示,待兴许測一下性能,假设还能够的话再做成自己定义控件。
先做一些声明:
1.这里只演示一个演示样例,说明这样的Banner的实现原理,暂未封装成控件
2.演示样例中手势滑动仅用button点击来模拟
3.因为仅演示原理。演示样例中未加入Indicator的联动效果,也没有Banner的点击响应
4.Banner的移动速度由动画时间控制,可自由设置。演示样例中设置的时间较短,故移动比較快
5.Banner尺寸临时写死了,仅适配Nexus4手机,其它手机測试请自行获取Banner宽度
6.请分别測试自己主动播放和左滑、右滑
7.上述问题皆可在封装成正式控件时解决,同一时候还有图片缓存等
8.另外Banner播放移动由属性动画控制。因此3.0下面需额外动画库nineoldandroids
先来看下效果图(动画录制的非常差,上两张静态图好了,大概能够看到Banner的移动过程):
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYWhlbmNl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" align="middle" width="428" height="830" alt="">
接下来说一下实现原理,眼下仅測试了自己主动播放广告和左右滑动广告。临时未处理自己主动播放过程中的左右滑动行为。
没啥美术功底,草纸上大概画了个示意图:
以下详细来解释一下:
1.首先说明支持随意张广告,个人測试用了4张,下面直接按4张解释原理了
2.先看Banner布局。
最外层放一个FrameLayout作为容器,之所以用FrameLayout,是由于兴许须要在广告条上覆盖Indicator,即小圆点指示器(眼下演示样例里没有)。FrameLayout放一个水平的LinearLayout。该LinearLayout中依次放4个ImageView。每一个代表一幅广告。须要注意的是,初始时。手机屏幕宽度内仅显示第一幅广告。其它3个ImageView能够理解为在手机屏幕右側看不见的位置。
3.再来说怎样实现广告位的移动。大家都知道属性动画与之前的动画最大的差别就是属性动画真实地改变了其属性,比方颜色、位置等。不错,正是利用这一点,对ImageView做动画。改编其水平位置属性。达到移动广告位的目的。详细的动画实现请參考下文中的代码。
4.接下来看怎样实现Banner自己主动播放。
開始时,同一时候对4个ImageView做属性动画,将它们都向左移动一个广告位的宽度。
第一次动画完毕后。它们的位置是这种:第1个广告能够理解为移动到了手机屏幕左边的位置,手机屏幕上显示的是第2个广告。第3个。第4个广告依旧在手机屏幕右側看不到的位置。然后再次对它们4个做上述移动的动画,就这样,做完一次动画再做一次,假设没有不论什么处理的话,等第4张也移动到手机屏幕左側,再做动画就什么都看不到了,由于它们已经远远偏离手机屏幕了。因此须要做一个特别处理。就是在4个ImageView每次动画完毕之后,检查自己的位置,是否已经处于手机屏幕左側了。假设是。则又一次设置一下自己的位置。这个位置也不是随便设置的,须要将它设置到右側最后,紧跟前一个广告。这样做的效果就是每当Banner移动一次。移到左边的广告条会自己主动被又一次放到右側末尾,而不影响视觉效果。从而能够达到循环播放的效果。个人认为这样做的优点是永远仅仅有4个ImageView对象。摒弃了取余循环的方式,效率应该会有提升。
5.最后说手动左滑右滑的实现原理。因为仅仅是演示原理,本例并未真正处理手势滑动,仅用button点击来模拟。假设一直向左滑动或向右滑动比較优点理,但手势滑动不像自己主动轮播,手势滑动可左一下。右一下。随意次数的左右滑动,因此也要做特殊处理。假设向左滑动。原理同自己主动播放,利用动画将4个ImageView左移一个广告位,随后将移到左側的又一次追加到右側最后边,不论什么一次左滑也是相同的处理。因此任一次左滑结束后,一个广告当前显示,其余3个都能够觉得在手机屏幕右側。对于右滑,不同于左滑。它须要在右滑之前做处理,我们须要在右滑之前先提供可供滑动的广告位,因此须要事先把最右边的广告位拿到手机屏幕左側,然后再运行右滑处理。事实上能够这样觉得。每次右滑之前。手机屏幕左側是没有广告位的,须要预先从最右側拿1幅广告到手机屏幕左側。
以下附一些相关代码,以下是演示样例的布局代码:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"> <FrameLayout
android:id="@+id/banner_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <ImageView
android:id="@+id/banner_1"
android:layout_width="704px"
android:layout_height="wrap_content"
android:src="@drawable/banner1" /> <ImageView
android:id="@+id/banner_2"
android:layout_width="704px"
android:layout_height="wrap_content"
android:src="@drawable/banner2" /> <ImageView
android:id="@+id/banner_3"
android:layout_width="704px"
android:layout_height="wrap_content"
android:src="@drawable/banner3" /> <ImageView
android:id="@+id/banner_4"
android:layout_width="704px"
android:layout_height="wrap_content"
android:src="@drawable/banner4" />
</LinearLayout> </FrameLayout> <Button
android:id="@+id/btn_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/banner_container"
android:text="自己主动轮播" /> <Button
android:id="@+id/btn_stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/btn_start"
android:enabled="false"
android:text="自己主动播放与滑动请分别測试" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/btn_stop"> <Button
android:id="@+id/btn_left"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="模拟左滑" /> <Button
android:id="@+id/btn_right"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="模拟右滑"/>
</LinearLayout> </RelativeLayout>
自己主动播放的处理代码:
/**
* 自己主动播放广告条,播放速度可由动画时间控制
*/
public void doAutoPlay() {
for (int i = 0; i < COUNT; i++) {
doAutoAnimation(imgArray[i]);
}
} /**
* 仅适用于自己主动播放
*
* @param v
*/
public void doAutoAnimation(final View v) {
v.animate().x(v.getX() - v.getWidth()).setDuration(1500).setInterpolator(new LinearInterpolator()).setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) { } @Override
public void onAnimationEnd(Animator animator) {
if (v.getX() < 0) {
v.setX((COUNT - 1) * v.getWidth());
} doAutoAnimation(v);
} @Override
public void onAnimationCancel(Animator animator) { } @Override
public void onAnimationRepeat(Animator animator) { }
});
}
向左滑动处理代码:
/**
* 模拟向左滑动Banner
*/
public void doLeftAnimation() {
for (int i = 0; i < COUNT; i++) {
doLeftAnimation(imgArray[i]);
}
} /**
* 左滑之后,将滑到左边看不到的广告位移动到右边末尾
*
* @param v
*/
public void doLeftAnimation(final View v) {
v.animate().x(v.getX() - v.getWidth()).setDuration(1500).setInterpolator(new LinearInterpolator()).setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) { } @Override
public void onAnimationEnd(Animator animator) {
if (v.getX() < 0) {
v.setX((COUNT - 1) * v.getWidth());
}
} @Override
public void onAnimationCancel(Animator animator) { } @Override
public void onAnimationRepeat(Animator animator) { }
});
}
向右滑动处理代码:
/**
* 模拟向右滑动Banner。
* 因为没有採用常规的设置一个非常大数,然后取余实现循环的原理;
* 本例默认N个Banner广告均在手机屏幕可见区域及右側(屏幕可见区域仅显示当前广告条)
* 因此向右滑动之前。须要预先将最右側的广告条移到手机屏幕左側不可见区域
*/
public void doRightAnimation() {
for (int i = 0; i < COUNT; i++) {
if (imgArray[i].getX() == imgArray[i].getWidth() * (COUNT - 1)) {
imgArray[i].setX(-imgArray[i].getWidth());
break;
}
} for (int i = 0; i < COUNT; i++) {
doRightAnimation(imgArray[i]);
}
} /**
* 在右滑之前须要先提供一个可向右滑动的广告位
*/
public void doRightAnimation(final View v) {
v.animate().x(v.getX() + v.getWidth()).setDuration(1500).setInterpolator(new LinearInterpolator()).setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) { } @Override
public void onAnimationEnd(Animator animator) { } @Override
public void onAnimationCancel(Animator animator) { } @Override
public void onAnimationRepeat(Animator animator) { }
});
}
完整演示样例代码下载 当某天须要下载资料时,发现自己居然没有下载积分,因此设了1个积分,有须要下载的能够支持下,多谢。
利用Android属性动画实现Banner的原理与实践的更多相关文章
- Android属性动画完全解析(上),初识属性动画的基本用法
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43536355 在手机上去实现一些动画效果算是件比较炫酷的事情,因此Android系 ...
- Android属性动画完全解析(中)
转载:http://blog.csdn.net/guolin_blog/article/details/43536355 大家好,在上一篇文章当中,我们学习了Android属性动画的基本用法,当然也是 ...
- Android属性动画完全解析(上)
Android属性动画完全解析(上) 转载:http://blog.csdn.net/guolin_blog/article/details/43536355 在手机上去实现一些动画效果算是件比较炫酷 ...
- Android 属性动画 源码解析 深入了解其内部实现
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/42056859,本文出自:[张鸿洋的博客] 我参加了博客之星评选,如果你喜欢我的博 ...
- 用Android属性动画实现和演示迪士尼动画基本原则
本文将介绍在Android平台上实现和演示迪士尼动画基本准则. 项目开源,GitHub: https://github.com/vhow/animation 说明: 演示动画原则的想法源自 Anima ...
- Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43536355 大家好,在上一篇文章当中,我们学习了Android属性动画的基本用法 ...
- 详解Android属性动画
前面我们讲到的属性动画都是使用代码的定义方式:Android属性动画之ValueAnimator和Android属性动画之ObjectAnimator和AnimatorSet,下面我们再来看看使用XM ...
- Android属性动画-基本用法
在手机上去实现一些动画效果算是件比较炫酷的事情,因此Android系统在一开始的时候就给我们提供了两种实现动画效果的方式,逐帧动画(frame-by-frame animation)和补间动画(twe ...
- Android属性动画完全解析
转载:http://blog.csdn.net/guolin_blog/article/details/43536355 在手机上去实现一些动画效果算是件比较炫酷的事情,因此Android系统在一开始 ...
随机推荐
- iOS系统自带的 UIAlertView 自动旋转的实现
这里主要解析 UIAlertView 的几个关键功能的实现: 随着设备屏幕的旋转而旋转: Alert弹出框,使用UIWindow来实现,就是说,不用依赖于当前显示在最前面的UIView. 实现源码参考 ...
- [HDU 4842]--过河(dp+状态压缩)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4842 过河 Time Limit: 3000/1000 MS (Java/Others) Mem ...
- USACO March. 2012
Connect the Cows Times17 水题 Landscaping Flowerpot Tractor 广搜 搜到边界就可以终止了 没什么难度 #include <stdio.h&g ...
- 我的Python成长之路---第三天---Python基础(10)---2016年1月16日(雾霾)
二.collections collections是对Python现有的数据类型的补充,在使用collections中的对象要先导入import collections模块 1.Counter——计数 ...
- Codeforces Round #254 (Div. 2) DZY Loves Chemistry【并查集基础】
一开始不知道题意是啥意思,迟放进去反应和后放进去反应有什么区别 对于第三组数据不是很懂,为啥312,132的组合是不行的 后来发现这是一道考察并查集的题目 QAQ 怒贴代码: #include < ...
- WebLech是一个功能强大的Web站点下载与镜像工具
WebLech是一个功能强大的Web站点下载与镜像工具.它支持按功能需求来下载web站点并能够尽可能模仿标准Web浏览器的行为.WebLech有一个功能控制台并采用多线程操作. http://sour ...
- BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )
这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------- ...
- Netty开发实现高性能的RPC服务器
Netty开发实现高性能的RPC服务器 RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协 ...
- asp.net core 使用 Redis 和 Protobuf
asp.net core 使用 Redis 和 Protobuf 前言 上篇博文介绍了怎么样在 asp.net core 中使用中间件,以及如何自定义中间件.项目中刚好也用到了Redis,所以本篇就介 ...
- C#中调用Windows API时的数据类型对应关系
原文 C#中调用Windows API时的数据类型对应关系 BOOL=System.Int32 BOOLEAN=System.Int32 BYTE=System.UInt16 CHAR=System. ...