[译]Workcation App – 第一部分 . 自定义 Fragment 转场动画
当滑动底部的 RecycleView item 的时候,地图上的标记会通过闪烁来显示它们的位置(译者注:原文是show their position on the map,个人认为 position 有两层含义:一代表标记在地图上的位置,二代表标记所对应的 item 在 RecycleView 里的位置。)
在点击一个 item 以后,我们会进入到新界面。在此界面中,地图通过动画方式来显示出路径以及起始/结束标记。同时此 RecyclerView 的item 会通过转场动画展示一些关于此地点的描述,背景图片也会放大,还附有更详细的信息和一个按钮。
当后退时,详情页通过转场变成普通的 RecycleView Item,所有的地图标记再次显示,同时路径一起消失。
就这么多啦,这就是我准备在这一系列文章中向你展示的东西。在本文中我会编写进入地图 fragment 的转场动画。
就像我们在 GIF 1 里看到的那样,看起来好像地图在移动到正确地点之前已经加载完毕了。这在真实世界里是不可能的,它实际上是这个样子的:
为地图编写一个包含缩放与渐显的自定义转场动画(transition),进入DetailsFragment 的时候就激活。
预加载地图
为了实现上述目标,我们首先从已加载的地图上拿到一份快照(snapshot)。当然我们如果想把转场动画做的更平滑一点,肯定不能等进入 DetailsFragment 后才获取。所以要怎么做呢?当然是是悄悄的在 HomeFragment 里拿到这个图片(bitmap) 并且保存在缓存里啦。地图距离底部还有一点距离(margin),所以我们拿到的图片必须满足"将来的"地图尺寸。
XHTML ?xml version="1.0"encoding="utf-8"? android.support.design.widget.CoordinatorLayout 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" xmlns:app="http://schemas.android.com/apk/res-auto" tools:MContext=".screens.main.MainActivity"
/android.support.design.widget.CoordinatorLayout
就像上面代码展示的那样,MapFragment 被放在布局的最下方,这样我们就可以在用户看不到地方加载地图。
public class MainActivity extends MvpActivity MainView,MainPresenter implements MainView,OnMapReadyCallback{ SupportMapFragment mapFragment; privateLatLngBounds mapLatLngBounds; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); presenter.provideMapLatLngBounds(); getSupportFragmentManager() .beginTransaction() .replace(R.id.container,HomeFragment.newInstance(),HomeFragment.TAG) .addToBackStack(HomeFragment.TAG) .commit(); mapFragment=(SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.mapFragment); mapFragment.getMapAsync(this);
MapsUtil.calculateHeight(getWindowManager(),getResources().getDimensionPixelSize(R.dimen.map_margin_bottom)), MapsUtil.DEFAULT_ZOOM)); googleMap.setOnMapLoadedCallback(()- googleMap.snapshot(presenter::saveBitmap)); }
MainActivity 继承自 MvpActivity,而 MvpActivity 是来自 Hannes Dorfmann 写的 Mosby Framework。我的项目都遵从 MVP 模式,而这个框架是一个 MVP 模式的非常好的实现。
在 onCreate 方法里我们做了三件事:
当地图加载完毕时,就会调用 onMapReady() 方法,我们就可以通过一些操作把当前加载的地图转换成 bitmap 图片。通过 CameraUpdateFactory.newLatLngBounds() 方法,我们可以把镜头转到之前提供的 LatLngBounds 上。这样的话我们就精确的知道下个页面的地图区域,再把屏幕宽度和高度当作参数传入 onMapReady() 方法,像这样操作:
public static int calculateWidth(final WindowManager windowManager){ DisplayMetrics metrics=newDisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(metrics); returnmetrics.widthPixels;
public static int calculateHeight(final WindowManager windowManager,finalintpaddingBottom){ DisplayMetrics metrics=newDisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(metrics); returnmetrics.heightPixels-paddingBottom;
很简单吧?在调用 googleMap.moveCamera() 方法以后,我们设置OnMapLoadedCallback 的回调。当镜头移动到正确的位置的时候,调用 onMapLoaded()方法,我们准备好在此处截图了。
获得图片并保存在缓存中onMapLoaded() 方法只做一件事 —— 在从地图上获得快照后调用 presenter.saveBitmap()方法。多亏 lambda 表达式,我们可以缩短代码到一行。(译者注:有关 lamb 表达式,推荐搭配此文章一起食用。)
googleMap.setOnMapLoadedCallback(()- googleMap.snapshot(presenter::saveBitmap));
此 presenter (译者注:MVP 里的 P) 的代码非常简单,它只是把图片保存在缓存里。
@Override public void saveBitmap(final Bitmap bitmap){ MapBitmapCache.instance().putBitmap(bitmap);
private static final int DEFAULT_CACHE_SIZE=(int)(Runtime.getRuntime().maxMemory()/1024)/8; public static final String KEY="MAP_BITMAP_KEY";
}
此处我使用了 LruCache ,因为这是比较推荐的做法,这里有详细解释。
现在我们把bitmap 存到了缓存里,剩下唯一要做的事情就是自定义一个缩放和渐进效果的转场动画。
毛毛雨洒洒水啦~(译者注: 原文为 Easy peasy lemon squeezy。是一个比较有意思的、以俏皮的语气表达“轻而易举”或者“手到擒来”概念的短语。)
下面是最有意思的部分,代码也炒鸡简单!但就是这部分完成了比较炫酷的事情。
public class ScaleDownImageTransition extends Transition{ private static final int DEFAULT_SCALE_DOWN_FACTOR = 8; private static final String PROPNAME_SCALE_X="transitions:scale_down:scale_x"; private static final String PROPNAME_SCALE_Y="transitions:scale_down:scale_y"; private Bitmap bitmap; private Context context;
TypedArray array=context.obtainStyledAttributes(attrs,R.styleable.ScaleDownImageTransition); try{ targetScaleFactor=array.getInteger(R.styleable.ScaleDownImageTransition_factor,DEFAULT_SCALE_DOWN_FACTOR); }finally{ array.recycle();
public Animator createAnimator(final ViewGroup sceneRoot,final TransitionValues startValues,final TransitionValues endValues){ if(null == endValues){ return null; final View view=endValues.view; if (view instanceof ImageView){ if (bitmap!=null) view.setBackground(new BitmapDrawable(context.getResources(),bitmap)); float scaleX=(float)startValues.values.get(PROPNAME_SCALE_X); float scaleY=(float)startValues.values.get(PROPNAME_SCALE_Y);
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(view,View.SCALE_X,targetScaleX,scaleX); ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(view,View.SCALE_Y,targetScaleY,scaleY); AnimatorSet set=new AnimatorSet(); set.playTogether(scaleXAnimator,scaleYAnimator,ObjectAnimator.ofFloat(view,View.ALPHA,0.f,1.f)); return set; return null;
captureValues(transitionValues,transitionValues.view.getScaleX(),transitionValues.view.getScaleY());
private void captureValues(final TransitionValues values,final float scaleX,final float scaleY){ values.values.put(PROPNAME_SCALE_X,scaleX); values.values.put(PROPNAME_SCALE_Y,scaleY); }
在转场动画中做了什么事情呢?我们用 scaleFactor 对传入的 imageView 进行了 scaleX 和 scaleY 属性的缩放(默认是8)。换句话说我们通过 scaleFactor 先把图片拉伸,然后再把图片压缩回需要的大小。
创建自定义转场动画为了编写转场动画,我们必须继承一个 Transition 类。然后重写 captureStartValues 和captureEndValues 方法。猜猜发生了啥?
Transition 框架使用了属性动画的 API ,通过改变 view 开始和结束时的属性值来产生动画。如果你不熟悉属性动画,强烈推荐阅读这篇文章。就像刚才解释的那样,我们要缩放图片。开始值是 scaleFactor ,结束值是期望 scaleX 和 scaleY的值,通常情况下是1。
怎么传递这些值呢?如前所述,很简单。我们把 TransitionValues 对象当作参数传进captureStart 和 captureEnd 方法里。它包括一个 view 的引用和一个可以保存值的 Map 对象,在我们的项目中需要保存的值就是 scaleX 和 scaleY。
获得这些值以后,我们需要重写 createAnimator() 方法。在这个方法中需要返回一个动态改变 view 属性的 Animator (或者 AnimatorSet )。本项目中返回的是 AnimatorSet 对象,此对象同时改变一个 view 的尺寸和亮度。同时,因为我们只希望转场动画作用在 ImageView 上,所以通过 instanceof 进行了对象类型校验,以保证传入的 view 是一个 ImageView。
部署自定义转场动画我们已经在缓存中保存了 bitmap 图片,也已经创建了转场动画,所以只剩最后一步 —— 就是为 fragment 添加转场动画。我喜欢写一个静态工厂方法来创建 fragments 和 activities 。这么做可以让我们保持代码逻辑清晰,所以也应该用这样的设计模式来编写转场动画的代码。
public static Fragment newInstance(final Context ctx){ DetailsFragment fragment = new DetailsFragment(); ScaleDownImageTransition transition=new ScaleDownImageTransition(ctx,MapBitmapCache.instance().getBitmap()); transition.addTarget(ctx.getString(R.string.mapPlaceholderTransition)); transition.setDuration(800); fragment.setEnterTransition(transition); return fragment; }
瞧,做起来多简单。我们为转场动画实例化了一个新的实例,又通过 xml 为它添加了transitionName 的属性。
ImageView android:id="@+id/mapPlaceholder" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="@dimen/map_margin_bottom" android:transitionName="@string/mapPlaceholderTransition"/
然后我们通过 setEnterTransition() 把fragment 传递进去, 看吧!效果出现啦:
你看,最终效果已经很接近像 GIF 那样从本地加载地图的效果了。但是最后一帧动画仍然会有那么一点闪烁,因为地图的快照还是与实际的地图有点差别。
多谢阅读,下一部分会在星期二的 7.03 更新。如果有疑问的话,欢迎评论。当然如果发现这些博文很有趣,不要忘记分享噢。
原文发布时间为:2017年6月05日 本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。uni-app导航栏自定义配置|仿App原生导航条 uniapp自带的原生导航条能满足一般项目需求,但是对于一些复杂导航栏,如:京东、淘宝、微信顶部导航,这时就需要进行自定义配置了。基于uniapp实现的自定义仿微信导航栏uni_headerBar,支持背景渐变、标题居左/居中、搜索条、按钮支持文字/字体图标/图片 uniApp原生导航栏 uni-app原生导航栏也能实现一些顶部自定义按钮+搜索框,只需在page.json里面做一些配置即可。
背水一战 Windows 10 (64) - 控件(WebView): 加载指定 HttpMethod 的请求, 自定义请求的 http header, app 与 js 的交互 原文:背水一战 Windows 10 (64) - 控件(WebView): 加载指定 HttpMethod 的请求, 自定义请求的 http header, app 与 js 的交互 [源码下载] 背水一战 Windows 10 (64) - 控件(WebView): 加载指定 HttpMeth...
SharePoint 2013 开发——开发自定义操作APP 博客地址:http://blog.csdn.net/FoxDave 自定义操作即我们所说的Ribbon和ECB(Edit Control Block),在SharePoint 2013之前,我们可以通过在解决方案中添加XML元素来实现创建自定义Ribbon和ECB,到了2013时代,利用APP也可以做类似的事情了,接下来我们看看如何利用APP来创建列表条目的自定义操作。
相关文章
- 如何设计APP版本号?
- 004_为什么不推荐APP使用SSL-PINNING
- 一种新的移动APP保持登陆的实现机制介绍
- iOS从0到1搭建高可用App框架
- 精品基于Uniapp+SSM实现的定制旅游APP
- 谈谈APP架构选型:React Native还是HBuilder
- Django 2 创建app
- NativeScript - JS 构建跨平台的原生 APP
- uniapp APP开发监听顶部返回按钮到指定页面
- 移动app传统测试流程优化
- 最新好看的自适应手机版软件APP下载类网站源码,游戏软件应用网站源码,自适应手机端Pbootcms模板
- [译]Workcation App – 第四部分. 场景(Scenes)和 RecyclerView 的共享元素转场动画(Shared Element Transition)
- [译]Workcation App – 第二部分 .带有动画的标记(Animating Markers) 与 MapOverlayLayout
- Android App自适应draw9patch不失真背景图
- Android Listview滑动时不加载数据,停下来时加载数据,让App更优
- 一键生成APP官网