Android 项目优化笔记(三):首页

一、首页优化问题

那么首先回顾一下有关首页的优化建议

  1. 角色切换方式 可以优化,如果更换的话可能需要 重新设计,且涉及逻辑较多,暂不更改。
  2. 用户登录时 提示用户选择角色。(Maybe)
  3. 角色切换可添加动画,用户操作时从左上角动画延伸至整个首页。Reveal Effect (揭露效果)。
  4. MD 风格:头部 CoordinatorLayout + AppBarLayout + Toolbar,AppBarLayout + Toolbar 可以抽出来。底部导航栏可用 BottomNavigationView 替换。

二、解决问题

问题 1 和问题 2

问题 1 和问题 2 需要产品和业务沟通,本文只讨论技术实现,略过。

问题 3:角色切换动画

问题 3 中提到的 Reveal Effect (揭露效果) 是 # Material-Animations 中的动画效果之一。其它的动画效果包括 Activity 之间转换动画、共享元素动画,以及布局转换动画(布局宽高或状态改变时以动画方式进行)。

那么先看一下揭露效果实例:


Android 项目优化笔记(三):首页_第1张图片
reveal_yellow.gif

我希望在切换角色后从切换按钮执行切换动画至全屏,但是实际做出来效果比较差。首先项目中首页的背景并不是纯色,就算是纯色进行揭露,还要考虑要切换成什么颜色...所以这里暂时不做成揭露效果...不过先画个饼,在以后的项目优化过程中,会在合适的地方用上这个效果。

但是可以做成 Transition 效果,整体效果如下:


整体效果

在这之前,需要简单了解一下 Transition 和 Scene 的概念。

Transition

看一下官方文档的解释:

A Transition holds information about animations that will be run on its targets during a scene change.

渣翻:Transition 包含了一些动画信息,在场景(Scene)转换时使用。

另外根据文档可知 Transition 主要工作有两个:

  1. 获取属性值
  2. 根据捕获的属性值的更改来播放动画。

那么 Transition 主要包含的类型有:

  • ChangeBounds:改变 View 的大小和位置
  • Fade:改变透明度
  • TransitionSet:组合动画
  • AutoTransition:默认的组合动画,封装淡出、改变View大小,最后淡入效果。
Scene

A scene represents the collection of values that various properties in the View hierarchy will have when the scene is applied.

渣翻:一个Scene是当前View所有属性的集合。比如一个布局里所有 View 的属性,包括它们的宽高等,都可以保存为一个 Scene。

这样 Scene 对象将提供一些属性值,再通过 Transition 的动画来改变这些属性值,以达成动画效果。

有关 Transition 和 Scene 的概念先记录到这里。考虑到该项目有三个角色:货主、承运商和司机,需要进行角色切换。且三个角色布局有所不同,所以比较适合使用 Transition + Scene 进行切换。下面就使用最简单的 AutoTransition 进行切换:

  1. 首先创建 Fragment 并写好点击事件,这里是通过点击 MainActivity Toolbar 的左侧 TextView 来展示 PopupMenu,然后再进行点选切换角色。比较简单就不贴代码了,可以在源码中查看。

MainActivity

  1. 写好三个角色的布局,以便进行转换。货主页面是默认页:
Android 项目优化笔记(三):首页_第2张图片
scene_carrier



    

    

    


很简单,一个 LinearLayout 裹着两个图片一个按钮。需要注意的是该 LinearLayout 将作为 viewRoot 使用,id 为 ll_parent。

其它两个页面大同小异,就不贴了。

  1. 根据不同角色类型进行转换,点击切换角色时将角色类型传递并转换到相应的布局:
public static final String USER_TYPE_CONSIGNOR = "货主";
public static final String USER_TYPE_CARRIER = "承运商";
public static final String USER_TYPE_DRIVER = "司机";
...
/**
 * 根据不同角色类型进行场景转换
 * @param type 类型
 */
public void transitionView(String type){
    switch (type){
        case Constants.USER_TYPE_CONSIGNOR:
            TransitionUtil.transitionLayout(ll_parent,R.layout.scene_consignor,getActivity());
            break;
        case Constants.USER_TYPE_CARRIER:
            TransitionUtil.transitionLayout(ll_parent,R.layout.scene_carrier,getActivity());
            break;
        case Constants.USER_TYPE_DRIVER:
            TransitionUtil.transitionLayout(ll_parent,R.layout.scene_driver,getActivity());
            break;
        default:
            break;
    }
}

*ll_parent:就是主页 xml 根布局,上面提到的 viewRoot。

TransitionUtil

/**
 * AutoTransition 转换
 * @param sceneRoot 根局部
 * @param layout 转换到的布局
 * @param context context
 */
public static void transitionLayout(ViewGroup sceneRoot, @LayoutRes int layout, Context context){
    Scene scene = Scene.getSceneForLayout(sceneRoot,layout,context);
    TransitionManager.go(scene);
}

看一下核心代码,进行 Transition 动画的三个要素:

  • Scene:调用 Scene#getSceneForLayout 传递根布局和要转换到的布局作为参数,生成 Scene 对象,这样储存了两个布局信息的 Scene 对象就产生了。
    创建 Scene 对象的方式还有另外几种,后面会记录。
  • TransitionManager:Transition 的管理者,使用该类的一些静态方法来执行转换。
  • Transition:TransitionManager 默认提供一个 AutoTransition,参考下面源码:

TransitionManager#go(@NonNull Scene scene)

private static Transition sDefaultTransition = new AutoTransition();
...
public static void go(@NonNull Scene scene) {
    changeScene(scene, sDefaultTransition);
}

只有一个 scene 参数的方法就使用默认的 AutoTransition。

TransitionManager#go(@NonNull Scene scene, @Nullable Transition transition)

public static void go(@NonNull Scene scene, @Nullable Transition transition) {
    changeScene(scene, transition);
}

上面的方法可以使用自定义的 Transition。

注意:

“承运商”页面有一个按钮有点击事件,但是该页面只是在进行 Transition 后才会加载,所以该按钮应该在“承运商”页面被转换后才能设置点击事件:

case Constants.USER_TYPE_CARRIER:
    TransitionUtil.transitionLayout(ll_parent,R.layout.scene_carrier,getActivity());
    ll_parent.findViewById(R.id.btn_carrier).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(getActivity(), "找货", Toast.LENGTH_SHORT).show();
        }
    });
总结:

创建 Scene 的方式有:

  • 直接 new:
    mScene1 = new Scene(mSceneRoot,mSceneRoot.findViewById(R.id.container));
  • 通过 Scene#getSceneForLayout静态方法创建:
    mScene2 = Scene.getSceneForLayout(mSceneRoot,R.layout.scene2,this);

创建 Transition 的方式有:

  • new 想要的动画类型:
    TransitionManager.go(scene1, new ChangeBounds());
  • 从xml创建
    TransitionManager.go(scene2, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds));

最后通过 TransitionManager 执行:

  • TransitionManager.go:一般配合 Scene 使用。
  • TransitionManager.beginDelayedTransition:不转换 Scene,只改变当前 View 状态可用此方法。

有关 Transition 和 Scene 还有很多内容,包括 5.0以上 Activity 的跳转也可以用 Transition,参考

Material-Animations

适配:
官方的只适配到 Android 5.0系统以上,这里有一个库可以支持到 4.0 系统:

Transitions-Everywhere

Transitions-Everywhere中文文档(译)

问题 4:MD 风格

首先搭一个常用的主体布局,ViewPager+Fragment。这样做的好处是既可以像微信一样左右滑动,又可以禁止滑动只能点选切换。比较简单,MainActivity。

接下来是 Toolbar,简单封装到 BaseActivity。因为教程也很多,这里略过,可以参考我简单封装的:BaseAppCompatActivity。

再然后是 BottomNavigationView,需要注意的是 BottomNavigationView 最多支持五个 item:

  1. 首先是导入 design 包,后面的版本最好与项目所用的 SDK 版本以及其它 Android 库相同:
implementation 'com.android.support:design:28.0.0'
  1. 创建 BottomNavigationView :



    

    
    
    
    


一些属性的解释:

  • app:itemIconTint 和 app:itemTextColor :分别代表 icon 填充色(针对 Vector 图片)和文字颜色。可以创建 selector 来根据状态改变颜色:

  
  
 
  • app:labelVisibilityMode:item 初始状态展示模式。
  1. menu,也就是上面指定的 app:menu="@menu/navigation"



    

    

    

    


可以指定 id、android:orderInCategory(指定item数字 id)、icon(图标)和 title(标题)。

注意事项:
*推荐使用 28 及以上版本的 BottomNavigationView,item 变多以后不会进行折叠
*app:labelVisibilityMode 是 28 版本才添加的功能,之前版本需要反射处理。

权限提示框

Dialog 就不赘述了,用 Google 推荐的 DialogFragment 把 Dialog 包起来就能达到不错的效果。放一个基础使用链接:

Android Dialog使用详解

如果有更多需求的话可以参考引用这个库:

material-dialogs

最后,贴上源码链接。

你可能感兴趣的:(Android 项目优化笔记(三):首页)