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 之间转换动画、共享元素动画,以及布局转换动画(布局宽高或状态改变时以动画方式进行)。

那么先看一下揭露效果实例:
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. 写好三个角色的布局,以便进行转换。货主页面是默认页:

scene_carrier

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:layout_marginTop="-50dp"
        android:src="@drawable/home_banner"
        android:adjustViewBounds="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_gravity="center_horizontal"
        android:src="@drawable/img_goods"
        android:adjustViewBounds="true"
        android:layout_width="200dp"
        android:layout_height="wrap_content" />

    <android.support.design.button.MaterialButton
        android:id="@+id/btn_consignor"
        android:layout_margin="16dp"
        android:text="发货"
        android:layout_width="match_parent"
        android:layout_height="56dp" />

</LinearLayout>

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

其它两个页面大同小异,就不贴了。
3. 根据不同角色类型进行转换,点击切换角色时将角色类型传递并转换到相应的布局:

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 :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <android.support.v4.view.ViewPager
        android:id="@+id/vp_home"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bnv_home"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:menu="@menu/navigation"
        app:labelVisibilityMode="labeled"/>
    
    <!--app:itemIconTint="@color/colorPrimary"-->
    <!--app:itemTextColor="@color/colorPrimary"-->

</LinearLayout>

一些属性的解释:

  • app:itemIconTint 和 app:itemTextColor :分别代表 icon 填充色(针对 Vector 图片)和文字颜色。可以创建 selector 来根据状态改变颜色:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item
      android:state_checked="true"
      android:color="@color/colorPrimary" />
  <item
      android:state_checked="false"
      android:color="@color/grey" />
 </selector>
  • app:labelVisibilityMode:item 初始状态展示模式。
  1. menu,也就是上面指定的 app:menu="@menu/navigation"
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/navigation_home"
        android:orderInCategory="0"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/title_home" />

    <item android:id="@+id/navigation_dashboard"
        android:orderInCategory="1"
        android:icon="@drawable/ic_dashboard_black_24dp"
        android:title="@string/title_1" />

    <item android:id="@+id/navigation_notifications"
        android:orderInCategory="2"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_2" />

    <item android:id="@+id/navigation_notifications2"
        android:orderInCategory="3"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_3" />

</menu>

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

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

权限提示框

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

Android Dialog使用详解

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

material-dialogs

最后,贴上源码链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值