app引导页(背景图片切换加各个页面动画效果)
前言:不知不觉中又加班到了10点半,整个启动页面做了一天多的时间,一共有三个页面,每个页面都有动画效果,动画效果调试起来麻烦,既要跟ios统一,又要匹配各种不同的手机,然后产品经理还有可能在中途改需求,程序员各种苦逼有木有,在这个过程中也学到了蛮多东西的,所以写一篇博客跟大家分享一下.
先看效果图:
1.显示三个页面的Activity 用view pager去加载三个fragment实现,控制点点点的切换,监听view pager的切换,控制fragment动画的开始跟结束,重写了view pager,实现了背景图片的移动效果.
- /**
- * 主Activity
- * @author ansen
- * @create time 2015-08-07
- */
- public class KaKaLauncherActivity extends FragmentActivity {
- private GuideViewPager vPager;
- private List<LauncherBaseFragment> list = new ArrayList<LauncherBaseFragment>();
- private BaseFragmentAdapter adapter;
- private ImageView[] tips;
- private int currentSelect;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_luancher_main);
- //初始化点点点控件
- ViewGroup group = (ViewGroup)findViewById(R.id.viewGroup);
- tips = new ImageView[3];
- for (int i = 0; i < tips.length; i++) {
- ImageView imageView = new ImageView(this);
- imageView.setLayoutParams(new LayoutParams(10, 10));
- if (i == 0) {
- imageView.setBackgroundResource(R.drawable.page_indicator_focused);
- } else {
- imageView.setBackgroundResource(R.drawable.page_indicator_unfocused);
- }
- tips[i]=imageView;
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
- layoutParams.leftMargin = 20;//设置点点点view的左边距
- layoutParams.rightMargin = 20;//设置点点点view的右边距
- group.addView(imageView,layoutParams);
- }
- //获取自定义viewpager 然后设置背景图片
- vPager = (GuideViewPager) findViewById(R.id.viewpager_launcher);
- vPager.setBackGroud(BitmapFactory.decodeResource(getResources(),R.drawable.bg_kaka_launcher));
- /**
- * 初始化三个fragment 并且添加到list中
- */
- RewardLauncherFragment rewardFragment = new RewardLauncherFragment();
- PrivateMessageLauncherFragment privateFragment = new PrivateMessageLauncherFragment();
- StereoscopicLauncherFragment stereoscopicFragment = new StereoscopicLauncherFragment();
- list.add(rewardFragment);
- list.add(privateFragment);
- list.add(stereoscopicFragment);
- adapter = new BaseFragmentAdapter(getSupportFragmentManager(),list);
- vPager.setAdapter(adapter);
- vPager.setOffscreenPageLimit(2);
- vPager.setCurrentItem(0);
- vPager.setOnPageChangeListener(changeListener);
- }
- /**
- * 监听viewpager的移动
- */
- OnPageChangeListener changeListener=new OnPageChangeListener() {
- @Override
- public void onPageSelected(int index) {
- setImageBackground(index);//改变点点点的切换效果
- LauncherBaseFragment fragment=list.get(index);
- list.get(currentSelect).stopAnimation();//停止前一个页面的动画
- fragment.startAnimation();//开启当前页面的动画
- currentSelect=index;
- }
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {}
- @Override
- public void onPageScrollStateChanged(int arg0) {}
- };
- /**
- * 改变点点点的切换效果
- * @param selectItems
- */
- private void setImageBackground(int selectItems) {
- for (int i = 0; i < tips.length; i++) {
- if (i == selectItems) {
- tips[i].setBackgroundResource(R.drawable.page_indicator_focused);
- } else {
- tips[i].setBackgroundResource(R.drawable.page_indicator_unfocused);
- }
- }
- }
- }
2.重写viewpager 在dispatchDraw方法中控制显示的背景图片区域,
- /**
- * 重写ViewPager 主要做一个切换背景的功能
- * @author ansen
- * @create time 2015-08-07
- */
- public class GuideViewPager extends ViewPager {
- private Bitmap bg;
- private Paint b = new Paint(1);
- public GuideViewPager(Context context) {
- super(context);
- }
- public GuideViewPager(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- @Override
- protected void dispatchDraw(Canvas canvas) {
- if (this.bg != null) {
- int width = this.bg.getWidth();
- int height = this.bg.getHeight();
- int count = getAdapter().getCount();
- int x = getScrollX();
- // 子View中背景图片需要显示的宽度,放大背景图或缩小背景图。
- int n = height * getWidth() / getHeight();
- /**
- * (width - n) / (count - 1)表示除去显示第一个ViewPager页面用去的背景宽度,剩余的ViewPager需要显示的背景图片的宽度。
- * getWidth()等于ViewPager一个页面的宽度,即手机屏幕宽度。在该计算中可以理解为滑动一个ViewPager页面需要滑动的像素值。
- * ((width - n) / (count - 1)) /getWidth()也就表示ViewPager滑动一个像素时,背景图片滑动的宽度。
- * x * ((width - n) / (count - 1)) / getWidth()也就表示ViewPager滑动x个像素时,背景图片滑动的宽度。
- * 背景图片滑动的宽度的宽度可以理解为背景图片滑动到达的位置。
- */
- int w = x * ((width - n) / (count - 1)) / getWidth();
- canvas.drawBitmap(this.bg, new Rect(w, 0, n + w, height), new Rect( x, 0, x + getWidth(), getHeight()), this.b);
- }
- super.dispatchDraw(canvas);
- }
- public void setBackGroud(Bitmap paramBitmap) {
- this.bg = paramBitmap;
- this.b.setFilterBitmap(true);
- }
- }
3.主体布局文件 上面放一个自定义的viewpager 下面放一个显示点点的RelativeLayout
- <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" >
- <com.example.view.GuideViewPager
- android:id="@+id/viewpager_launcher"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <RelativeLayout
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
- <LinearLayout
- android:id="@+id/viewGroup"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_marginBottom="30dp"
- android:gravity="center_horizontal"
- android:orientation="horizontal" />
- </RelativeLayout>
- </RelativeLayout>
4.ViewPager适配器
- /**
- * Viewpager适配器
- * @author apple
- *
- */
- public class BaseFragmentAdapter extends FragmentStatePagerAdapter {
- private List<LauncherBaseFragment>list;
- public BaseFragmentAdapter(FragmentManager fm, List<LauncherBaseFragment> list) {
- super(fm);
- this.list = list;
- }
- public BaseFragmentAdapter(FragmentManager fm) {
- super(fm);
- }
- @Override
- public Fragment getItem(int arg0) {
- return list.get(arg0);
- }
- @Override
- public int getCount() {
- return list.size();
- }
- }
5.Fragment抽象类 有两个抽象方法,开启动画跟停止动画 所有的Fragment都继承这个类 Viewpager切换的时候可以更好的控制每个Fragment开启动画,结束动画
- /**
- * Fragment抽象类
- * @author ansen
- *
- */
- public abstract class LauncherBaseFragment extends Fragment{
- public abstract void startAnimation();
- public abstract void stopAnimation();
- }
6.打赏页Fragment 三个动画效果 硬币向下移动动画+打赏图片缩放动画+改变打赏图片透明度然后隐藏图片
- /**
- * 打赏页面
- * @author ansen
- * @create time 2015-08-07
- */
- public class RewardLauncherFragment extends LauncherBaseFragment{
- private ImageView ivReward;
- private ImageView ivGold;
- private Bitmap goldBitmap;
- private boolean started;//是否开启动画(ViewPage滑动时候给这个变量赋值)
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
- View rooView=inflater.inflate(R.layout.fragment_reward_launcher, null);
- ivGold=(ImageView) rooView.findViewById(R.id.iv_gold);
- ivReward=(ImageView) rooView.findViewById(R.id.iv_reward);
- //获取硬币的高度
- goldBitmap=BitmapFactory.decodeResource(getActivity().getResources(),R.drawable.icon_gold);
- startAnimation();
- return rooView;
- }
- public void startAnimation(){
- started=true;
- //向下移动动画 硬币的高度*2+80
- TranslateAnimation translateAnimation=new TranslateAnimation(0,0,0,goldBitmap.getHeight()*2+80);
- translateAnimation.setDuration(500);
- translateAnimation.setFillAfter(true);
- ivGold.startAnimation(translateAnimation);
- translateAnimation.setAnimationListener(new AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {}
- @Override
- public void onAnimationEnd(Animation animation){
- if(started){
- ivReward.setVisibility(View.VISIBLE);
- //硬币移动动画结束开启缩放动画
- Animation anim=AnimationUtils.loadAnimation(getActivity(),R.anim.reward_launcher);
- ivReward.startAnimation(anim);
- anim.setAnimationListener(new AnimationListener(){
- @Override
- public void onAnimationStart(Animation animation) {}
- @Override
- public void onAnimationRepeat(Animation animation) {}
- @Override
- public void onAnimationEnd(Animation animation) {
- //缩放动画结束 开启改变透明度动画
- AlphaAnimation alphaAnimation=new AlphaAnimation(1,0);
- alphaAnimation.setDuration(1000);
- ivReward.startAnimation(alphaAnimation);
- alphaAnimation.setAnimationListener(new AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {}
- @Override
- public void onAnimationRepeat(Animation animation) {}
- @Override
- public void onAnimationEnd(Animation animation) {
- //透明度动画结束隐藏图片
- ivReward.setVisibility(View.GONE);
- }
- });
- }
- });
- }
- }
- @Override
- public void onAnimationRepeat(Animation animation) {}
- });
- }
- @Override
- public void stopAnimation(){
- started=false;//结束动画时标示符设置为false
- ivGold.clearAnimation();//清空view上的动画
- }
- }
7.私信页面 四个动画效果 并且四个动画都相同,其实只要我们实现了一个,其他的基本都很容易了. 依次实现四个图片的放大然后还原
- /**
- * 私信
- * @author ansen
- */
- public class PrivateMessageLauncherFragment extends LauncherBaseFragment{
- private ImageView ivLikeVideo,ivThinkReward,ivThisWeek,ivWatchMovie;
- private Animation likeAnimation,thinkAnimation,watchAnimation,thisWeekAnimation;
- private boolean started;//是否开启动画
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
- View rooView=inflater.inflate(R.layout.fragment_private_message_launcher, null);
- ivLikeVideo=(ImageView) rooView.findViewById(R.id.iv_private_message_like_video);
- ivThinkReward=(ImageView) rooView.findViewById(R.id.iv_private_message_think_reward);
- ivWatchMovie=(ImageView) rooView.findViewById(R.id.iv_private_message_watch_movie);
- ivThisWeek=(ImageView) rooView.findViewById(R.id.private_message_this_week);
- return rooView;
- }
- public void stopAnimation(){
- //动画开启标示符设置成false
- started=false;
- /**
- * 清空所有控件上的动画
- */
- ivLikeVideo.clearAnimation();
- ivThinkReward.clearAnimation();
- ivWatchMovie.clearAnimation();
- ivThisWeek.clearAnimation();
- }
- public void startAnimation(){
- started=true;
- /**
- * 每次开启动画前先隐藏控件
- */
- ivLikeVideo.setVisibility(View.GONE);
- ivThinkReward.setVisibility(View.GONE);
- ivWatchMovie.setVisibility(View.GONE);
- ivThisWeek.setVisibility(View.GONE);
- new Handler().postDelayed(new Runnable() {//延时0.5秒之后开启喜欢视频动画
- @Override
- public void run(){
- if(started)
- likeVideoAnimation();
- }
- },500);
- }
- /**
- * 好喜欢你的视频
- */
- private void likeVideoAnimation(){
- ivLikeVideo.setVisibility(View.VISIBLE);
- likeAnimation = AnimationUtils.loadAnimation(getActivity(),R.anim.private_message_launcher);
- ivLikeVideo.startAnimation(likeAnimation);//开启动画
- likeAnimation.setAnimationListener(new AnimationListener(){
- @Override
- public void onAnimationStart(Animation animation) {}
- @Override
- public void onAnimationRepeat(Animation animation) {}
- @Override
- public void onAnimationEnd(Animation animation) {//监听动画结束
- if(started)
- thinkReward();
- }
- });
- }
- /**
- * 谢谢你的打赏
- */
- private void thinkReward(){
- ivThinkReward.setVisibility(View.VISIBLE);
- thinkAnimation = AnimationUtils.loadAnimation(getActivity(),R.anim.private_message_launcher);
- ivThinkReward.startAnimation(thinkAnimation);
- thinkAnimation.setAnimationListener(new AnimationListener(){
- @Override
- public void onAnimationStart(Animation animation) {}
- @Override
- public void onAnimationRepeat(Animation animation) {}
- @Override
- public void onAnimationEnd(Animation animation) {
- if(started)
- watchMovie();
- }
- });
- }
- /**
- * 一起看个电影呗
- */
- private void watchMovie(){
- ivWatchMovie.setVisibility(View.VISIBLE);
- watchAnimation = AnimationUtils.loadAnimation(getActivity(),R.anim.private_message_launcher);
- ivWatchMovie.startAnimation(watchAnimation);
- watchAnimation.setAnimationListener(new AnimationListener(){
- @Override
- public void onAnimationStart(Animation animation) {}
- @Override
- public void onAnimationRepeat(Animation animation) {}
- @Override
- public void onAnimationEnd(Animation animation) {
- if(started)
- thisWeek();
- }
- });
- }
- /**
- * 好啊 这周末有空
- */
- private void thisWeek(){
- ivThisWeek.setVisibility(View.VISIBLE);
- thisWeekAnimation = AnimationUtils.loadAnimation(getActivity(),R.anim.private_message_launcher);
- ivThisWeek.startAnimation(thisWeekAnimation);
- }
- }
8.最后一个引导页 就两个动画 图片的放大跟缩小,其实用xml布局的话一个动画就能搞定,跟私信页面的动画差不多.小伙伴写的代码.这里换了一种方式.代码比较多.
- /**
- * 最后一个
- * @author apple
- */
- public class StereoscopicLauncherFragment extends LauncherBaseFragment implements OnClickListener{
- private static final float ZOOM_MAX = 1.3f;
- private static final float ZOOM_MIN = 1.0f;
- private ImageView imgView_immediate_experience;
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
- View rooView=inflater.inflate(R.layout.fragment_stereoscopic_launcher, null);
- imgView_immediate_experience=(ImageView) rooView.findViewById(R.id.imgView_immediate_experience);
- imgView_immediate_experience.setOnClickListener(this);
- return rooView;
- }
- public void playHeartbeatAnimation(){
- /**
- * 放大动画
- */
- AnimationSet animationSet = new AnimationSet(true);
- animationSet.addAnimation(new ScaleAnimation(ZOOM_MIN, ZOOM_MAX, ZOOM_MIN, ZOOM_MAX, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f));
- animationSet.addAnimation(new AlphaAnimation(1.0f, 0.8f));
- animationSet.setDuration(500);
- animationSet.setInterpolator(new AccelerateInterpolator());
- animationSet.setFillAfter(true);
- animationSet.setAnimationListener(new AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {
- }
- @Override
- public void onAnimationRepeat(Animation animation) {
- }
- @Override
- public void onAnimationEnd(Animation animation) {
- /**
- * 缩小动画
- */
- AnimationSet animationSet = new AnimationSet(true);
- animationSet.addAnimation(new ScaleAnimation(ZOOM_MAX, ZOOM_MIN, ZOOM_MAX,ZOOM_MIN, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f));
- animationSet.addAnimation(new AlphaAnimation(0.8f, 1.0f));
- animationSet.setDuration(600);
- animationSet.setInterpolator(new DecelerateInterpolator());
- animationSet.setFillAfter(false);
- // 实现心跳的View
- imgView_immediate_experience.startAnimation(animationSet);
- }
- });
- // 实现心跳的View
- imgView_immediate_experience.startAnimation(animationSet);
- }
- @Override
- public void onClick(View v) {
- // Intent intent = new Intent();
- // intent.setClass(getActivity(),MainActivity.class);
- // startActivity(intent);
- // getActivity().finish();
- }
- @Override
- public void startAnimation() {
- playHeartbeatAnimation();
- }
- @Override
- public void stopAnimation() {
- }
- }
最后总结:以上就是三个引导页的核心代码了,还有一些布局文件,动画效果的布局文件我就不一一贴出来的,大家可以去下载我的源码,在这个过程中碰到的几个大的问题说明一下.
1.viewpager切换的时候要结束上个fragment的动画 我是通过boolean变量去控制的
2.背景图片移动的效果 之前自己走了很多弯路,后面在网上找了一个demo拿过来用了.因为大家都有开源精神所以这里省了很多功夫
3.图片放大缩小以前居然不知道一个xml动画布局就能搞定.之前一直想办法用两个动画实现
看看时间一篇博客写了一个半小时,都12点了,办公室一个人敲打着键盘,记录着这两天做过的东西,才发现这也是一件很惬意的事情。。。。闪人。。。回家.
推荐下自己创建的android QQ群:202928390 欢迎大家的加入.
如果你想第一时间看我们的后期文章,扫码关注公众号,每个周末都会推送Android开发实战教程一篇,其余时间我们会推出一些互联网行业新闻,你还等什么,赶快关注吧,既能学到技术,还能长逼格,出任ceo,赢取白富美。。。。。
app引导页(背景图片切换加各个页面动画效果)的更多相关文章
- [Android实例] app引导页(背景图片切换加各个页面动画效果)(申明:来源于网络)
[Android实例] app引导页(背景图片切换加各个页面动画效果)(申明:来源于网络) 地址: http://www.eoeandroid.com/thread-918356-1-1.html h ...
- 高仿京东到家APP引导页炫酷动画效果
前言 京东到家APP的引导页做的可圈可点,插画+动效,简明生动地说明了APP最吸引用户的几个亮点(商品多,价格低,配送快...).本文主要分析拆解这些动画效果,并完成一个高仿Demo,完整的Demo代 ...
- iOS - GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD - ②)
距上一篇博客"APP引导页的高度集成 - DHGuidePageHUD - ①"的发布有一段时间了, 后来又在SDK中补充了一些新的内容进去但是一直没来得及跟大家分享, 今天来跟大 ...
- iOS - GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD - ①)
好长时间没更新博客, 是时候来一波干货分享了;APP引导页话不多说每一个APP都会用到,分量不重但是不可缺少,不论是APP的首次安装还是版本的更新,首先展现给用户眼前的也就只有它了吧,当然这里讲的不是 ...
- GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD)
每一个APP都会用到APP引导页,分量不重但是不可缺少,不论是APP的首次安装还是版本的更新,首先展现给用户眼前的也就只有它了,当然这里讲的不是APP引导页的美化而是APP引导页的高度集成,一行代码搞 ...
- Ubuntu18.04 更改GRUB引导菜单背景图片和默认启动项
一.更改GRUB引导菜单背景图片1.首先准备一张想要的照片,文件名是啥无所谓,只要格式是*.jpg *.JPG *.jpeg *.JPEG *.png *.PNG *.tga *.TGA都行,都能自动 ...
- HTML5+javascript实现图片加载进度动画效果
在网上找资料的时候,看到网上有图片加载进度的效果,手痒就自己也写了一个. 图片加载完后,隐藏loading效果. 想看加载效果,请ctrel+F5强制刷新或者清理缓存. 效果预览: 0% // ...
- [Swift通天遁地]五、高级扩展-(11)图像加载Loading动画效果的自定义和缓存
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- Android--ViewPager制作APP引导页
ViewPager使用FragmentStatePagerAdapter做Adapter,引导页使用多Fragment形式. FragmentStatePagerAdapter代码如下: public ...
随机推荐
- [C#] async 的三大返回类型
async 的三大返回类型 序 博主简单数了下自己发布过的异步文章,已经断断续续 8 篇了,这次我想以 async 的返回类型为例,单独谈谈. 异步方法具有三个可让开发人员选择的返回类型:Task&l ...
- 分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)
分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间) 很多时候我们都需要计算数据库中各个表的数据量和每行记录所占用空间 这里共享一个脚本 CREATE TABLE #tab ...
- ABP文档 - Mvc 控制器
文档目录 本节内容: 简介 AbpController基类 本地化 其它 过滤 异常处理和结果包装 审计日志 验证 授权 工作单元 反伪造 模型绑定器 简介 ABP通过nuget包Abp.Web.Mv ...
- hadoop 2.7.3本地环境运行官方wordcount-基于HDFS
接上篇<hadoop 2.7.3本地环境运行官方wordcount>.继续在本地模式下测试,本次使用hdfs. 2 本地模式使用fs计数wodcount 上面是直接使用的是linux的文件 ...
- Gradle 实现 Android 多渠道定制化打包
Gradle 实现 Android 多渠道定制化打包 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在项目中遇到需要实现 Apk 多渠道.定制化打包, Google .百度查找了一些资料, ...
- 一个表缺失索引发的CPU资源瓶颈案例
背景 近几日,公司的应用团队反应业务系统突然变慢了,之前是一直比较正常.后与业务部门沟通了解详情,得知最近生意比较好,同时也在做大的促销活动,使得业务数据处理的量出现较大的增长,最终系统在处理时出现瓶 ...
- 设计模式之创建类模式大PK
创建类模式大PK 创建类模式包括工厂方法模式.建造者模式.抽象工厂模式.单例模式和原型模式,他们能够提供对象的创建和管理职责.其 ...
- Python 正则表达式入门(中级篇)
Python 正则表达式入门(中级篇) 初级篇链接:http://www.cnblogs.com/chuxiuhong/p/5885073.html 上一篇我们说在这一篇里,我们会介绍子表达式,向前向 ...
- Android—自定义开关按钮实现
我们在应用中经常看到一些选择开关状态的配置文件,做项目的时候用的是android的Switch控件,但是感觉好丑的样子………… 个人认为还是自定义的比较好,先上个效果图:
- 如何搭建git服务器
一.前言 现在越来越多的公司用git进行版本控制,不过git是默认是开源的,如果私有的话是需要付费的,如果不想付费自己可以搭建一个git服务器用来版本控制. 二.服务器端操作 1.安装git sudo ...