android应用框架系列三,兼容性
2015-10-19 16:20
579 查看
A useful stack on android #3, compatibility
12 Mar 2015原文链接:http://saulmm.github.io/a-useful-stack-on-android-3-compatibility/原文作者:Saúl
Molinero
这是‘A useful stack on Android’系列的第三篇。
在第一部分我尝试定义一个模块化的可扩展的架构,基于设计模式: Model
View Presenter (MVP).
在第二部分 我解释如何使用一点点 Material
Design 技术在我们的用户界面,例如colors, transitions, vectors, 等等。
在第三部分,我将讲一讲兼容性,众所周知Android碎片化非常严重,版本不同,屏幕不同,特性,等等。
因为这个原因,我们将从最初到当前(Lollipop)的版本中减少一些支持,并且会支持不同的屏幕尺寸。
所有这些可在GitHUb获取到 - https://github.com/saulmm/Material-Movies
Downgrading SDK Levels
我选择Android SDK版本等级为16,从 Dashboards 上Google公布的数据,Jelly Bean 拥有的设备数是一个吸引人的数目86,8%。
需要支持这些版本,一些小的改变是必要的,例如 transitions with
shared elements,还没有被介绍直到21版本的Android框架。
Shared element transitions
当你在 MoviesActivity按下一个电影,需要检查版本号是否大于或等于Lollipop(21),如果有,我们可以使用新的API实现transitions
with shared elements (在例子中使用电影海报);如果没有,我使用一个动画达到一个相似的效果。
MoviesActivity
[code]@Override public void onClick(View v, int position, float touchedX, float touchedY) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) startSharedElementPosition(touchedView, position, movieDetailActivityIntent); else startDetailActivityAnimation(touchedView, (int) touchedX, (int) touchedY, movieDetailActivityIntent); }
为了替换两个activity之间切换使用一个共享元素,在
MovieDetailActivity,我将会从上个点到用户点击的点缩放电影海报。
MovieDetailActivity.java
[code]@Override public void onCreate(Bundle savedInstanceState) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) configureEnterTransition (); else { mViewLastLocation = getIntent() .getIntArrayExtra("view_location"); configureEnterAnimation (); } }
[code]private void configureEnterAnimation() { GUIUtils.startScaleAnimationFromPivot( mViewLastLocation[0], mViewLastLocation[1], mObservableScrollView, new AnimatorAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); GUIUtils.showViewByScale(mFabButton); } } ); animateElementsByScale(); }
GuiUtils.java
[code]public static void startScaleAnimationFromPivot ( int pivotX, int pivotY, final View v, final AnimatorListener animatorListener) { final AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator(); v.setScaleY(SCALE_START_ANCHOR); v.setPivotX(pivotX); v.setPivotY(pivotY); v.getViewTreeObserver().addOnPreDrawListener( new OnPreDrawListener() { @Override public boolean onPreDraw() { v.getViewTreeObserver().removeOnPreDrawListener(this); ViewPropertyAnimator viewPropertyAnimator = v.animate() .setInterpolator(interpolator) .scaleY(1) .setDuration(SCALE_DELAY); if (animatorListener != null) viewPropertyAnimator.setListener( animatorListener); viewPropertyAnimator.start(); return true; } }); }
VectorDrawables & Slide transition
另一个需要兼容的是 VectorDrawables,直到SDK 21版本才被介绍,用来替代它的是我显示了一个小的缩放和旋转的星星动画,使用
ViewPropertyAnimator制造。
动画: CircularReveal,在LLolipop之前不被支持,所以用相同的办法转换,我定义一个从上个点击点缩放的view。
MovieDetailActivity.java
[code]@Override public void showConfirmationView() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) GUIUtils.showViewByRevealEffect(mConfirmationContainer, mFabButton, GUIUtils.getWindowWidth(this)); else GUIUtils.startScaleAnimationFromPivot( (int) mFabButton.getX(),(int) mFabButton.getY(), mConfirmationContainer, null); animateConfirmationView(); startClosingConfirmationView(); }
MovieDetailActivity.java
[code]@Override public void animateConfirmationView() { Drawable drawable = mConfirmationView.getDrawable(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) if (drawable instanceof Animatable) ((Animatable) drawable).start(); else mConfirmationView.startAnimation( AnimationUtils.loadAnimation(this, R.anim.appear_rotate)); } }
效果:
Supporting different screen sizes
众所周知,android能在许多设备上运行,适配不同大小质量的屏幕是重要的,确保在4~12吋的屏幕上能正常显示,需要遵循下面几条指南。
Autofit RecyclerView
电影被排列在一个由GridLayoutManager管理的RecyclerView网格中。Google提供了一个constructor (构造函数),带有一个spanCount参数设置列的行数。
[code]public GridLayoutManager (Context context, int spanCount)
现在的问题是根据屏幕宽度我们需要显示多少行。
GridView view 为了这个目的实现了一个属性
android:numColumns = "auto_fit",不幸的是,没有在
RecyclerView实现这个属性,解决这个问题的办法是重用属性达到相同的目的。
Chiu-Ki Chan已经见过这个问题,而且她在她的blog里已经解决了这个问题。一般来说设置参数
spanCount取决与屏幕宽度。
效果:
Multiples resources
资源在android框架的角色是无可争辩的,通常的经验是用户使用nexus 5和nexus 10吋的显示效果完全不同,MoviesDetailActivity有不同的元素(图片等)根据屏幕显示。
得到这个结果的优化是最少的修改都在实际的 activity,
MovieDetailActivity做为布局的layout
activity_detail.xml
对此,请看应用的资源目录:
我们可以分以下几点显著区别设备:
少于600dp屏幕宽度的设备使用无修饰的-w600dp的文件夹,这里你能分类大多数手机,例如:nexus 5, nexus 4, 等。
超过600dp屏幕宽度的设备将会分为三个类型: -w600dp, -w600dp-land and -w600dp-port.
通过这种途径,我们可以根据我们自己找到的屏幕在不同的目录配置自己的layouts和dimensions。
同样的问题,
VectorDrawable在版本21之前不可用,所以-v21文件夹是为了这个目的(只有版本大于等于21才会使用-v21中的资源)。
例如,
ImageView显示
VectorDrawable星星,在不同的版本上是不一样的。 (
<include>).
activity_detail.xml (all versions)
[code]<FrameLayout> <!-- awesome hidden code --> <include layout="@layout/imageview_star" /> </FrameLayout>
imageview_star.xml (layout-v21)
[code]<?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_detail_confirmation_image" android:layout_width="300dp" android:layout_height="300dp" android:layout_gravity="center" android:src="@drawable/avd_star" />
imageview_star.xml (layout)
[code]<?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_detail_confirmation_image" android:layout_width="150dp" android:layout_height="150dp" android:layout_gravity="center" android:src="@drawable/star" />
我实现了这个解决方案,但是资源的模块化提供了许多可能的解决方案,例如,宽度和高度可以指定文件夹values/dimen.xml 和 values-v21/dimen.xml的尺寸,例如:
150dp和
300dp;
drawable可以矢量的叫做drawable-v21/star.
xml 或者叫做drawable/start.png。
Parallax landscape view
如果你查看Google Books APP,你会在Toolbar下面看到一个小的view,当和
Toolbar之间以不同的速度滑动书的列表将会出现一个
Parallax效果。
这里有一个很好系列文章叫做 How to hide/show Toolbar when list is srolling,作者是Michal
Z。对这个主题有深入的研究。
For layouts '-w600dp-land' and higher:
[code] <View android:id="@+id/activity_movies_background_view" android:layout_width="match_parent" android:layout_height="@dimen/ activity_movies_background_view_height" android:background="@color/theme_primary" />`
这个view由ButterKnife注入,但是在现有的nexus 5,将会从文件夹(layout)中寻找'activity_movies.xml' ,实际上这个view不存在于'activity_movies.xml' ,所以我们必须使用注解’@Optional‘标记这个view
。
MoviesActivity.java
[code]@Optional @InjectView(R.id.activity_movies_background_view) View mTabletBackground;
MoviesActivity.java
[code]private RecyclerView.OnScrollListener recyclerScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // awesome hidden code here if (mTabletBackground != null) { mBackgroundTranslation = mTabletBackground .getY() - (dy / 2); mTabletBackground.setTranslationY(mBackgroundTranslation); } }
相关文章推荐
- Android中的Shape使用总结
- Android如何使用命令行查看数据库SQLite3
- IDA动态调试Android的DEX文件
- Android开发总结笔记 四大组件之BroadcastReceiver 1-2-7
- android蛋疼的OOM
- android 串口调试
- Android支付宝集成
- AndroidStudio的一些坑
- WAYS TO UPDATE YOUR DEVICE
- Android init.rc文件解析过程详解(一)
- android应用框架系列二,图形界面
- AndroidStudio提交代码到Github(详细图文)
- android studio 在release打包时修改AndroidManifest.xml
- Android按返回键退出程序但不销毁,程序后台运行,同QQ退出处理方式
- [转载]Google Android开发精华教程
- 将Eclipse代码导入到AndroidStudio的两种方式
- Android:Android 6.0新特性
- 用Gradle 构建你的android程序-依赖管理篇
- android两个含有图片的TextView控件如何并列对称水平摆放
- 用Gradle 构建你的android程序