A useful stack on android #3, compatibility

这是‘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

@Overridepublic 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

@Overridepublic void onCreate(Bundle savedInstanceState) {    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)         configureEnterTransition ();     else {        mViewLastLocation = getIntent()            .getIntArrayExtra("view_location");        configureEnterAnimation ();    }}
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

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

@Overridepublic 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

@Overridepublic 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 参数设置列的行数。

public GridLayoutManager (Context context, int spanCount)

现在的问题是根据屏幕宽度我们需要显示多少行。

GridViewview 为了这个目的实现了一个属性android:numColumns = "auto_fit",不幸的是,没有在RecyclerView实现这个属性,解决这个问题的办法是重用属性达到相同的目的。

Chiu-Ki Chan已经见过这个问题,而且她在她的blog里已经解决了这个问题。一般来说设置参数spanCount取决与屏幕宽度。

效果:


Multiples resources

资源在android框架的角色是无可争辩的,通常的经验是用户使用nexus 5和nexus 10吋的显示效果完全不同,MoviesDetailActivity有不同的元素(图片等)根据屏幕显示。


得到这个结果的优化是最少的修改都在实际的 activity,MovieDetailActivity做为布局的layoutactivity_detail.xml

对此,请看应用的资源目录:


我们可以分以下几点显著区别设备:

  • 少于600dp屏幕宽度的设备使用无修饰的-w600dp的文件夹,这里你能分类大多数手机,例如:nexus 5, nexus 4, 等。

  • 超过600dp屏幕宽度的设备将会分为三个类型:-w600dp,-w600dp-landand-w600dp-port.

通过这种途径,我们可以根据我们自己找到的屏幕在不同的目录配置自己的layouts和dimensions。

同样的问题,VectorDrawable在版本21之前不可用,所以-v21文件夹是为了这个目的(只有版本大于等于21才会使用-v21中的资源)。

例如,ImageView显示VectorDrawable星星,在不同的版本上是不一样的。(<include>).

activity_detail.xml(all versions)

<FrameLayout>    <!-- awesome hidden code -->    <include        layout="@layout/imageview_star"    /></FrameLayout>

imageview_star.xml(layout-v21)

<?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)

<?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.xmlvalues-v21/dimen.xml的尺寸,例如:150dp300dp;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:

    <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

@Optional@InjectView(R.id.activity_movies_background_view) View mTabletBackground;

MoviesActivity.java

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);        }    }

更多相关文章

  1. Android中获得屏幕的尺寸
  2. 如何编译MTK android模拟器
  3. Android(安卓)Studio 导入项目时遇到sdk location not found错误
  4. ionic3 升级
  5. Android(安卓)Sqlite使用中注意事项
  6. Android(安卓)Studio1.5使用和学习记录
  7. Android系统信息获取 之二:版本信息获取
  8. Android(安卓)studio配置Google play服务
  9. Android全屏(包含3种隐藏顶部状态栏及标题栏和一种隐藏Android(安

随机推荐

  1. Android(安卓)抖动效果
  2. android监听软键盘退格(删除)事件
  3. launcher学习
  4. EditText光标居上
  5. Android:官网ROM下载地址备份
  6. Android(安卓)Wear 进阶 综述 Developing
  7. Android(安卓)签名验证
  8. 只发起单独activity
  9. 【Android】常见布局xml参数详解
  10. Android(安卓)debug.keystore的key和密码