人升开发日志#2 | 6/7 引导页

继续鸽需求文档,突然想要开始敲 Android 端的代码。

本文主要涉及到:

  • ViewPager + Fragment 组合使用
  • 沉浸式状态栏
  • 页面指示器框架
  • 使用 Lottie 框架显示动画
  • ViewPager 的简单优化
  • ViewPager 背景色渐变
  • Android Studio 录制手机屏幕

先发一下最终效果:


ViewPager + Fragment 组合使用

引导页一般是多页设计,所以我们这里用到 ViewPager 来切换不同的 Fragment。

新建 Activity 的时候可以选择 Tabbed Activity 作参考。

里面实现了 ViewPager 和 Fragment 的组合使用。

毕竟不是教程文档,我们这里仅做简单解释。

首先是活动布局文件 activity_welcome.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="net.sarasarasa.lifeup.WelcomeActivity">


<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

<me.relex.circleindicator.CircleIndicator
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginBottom="32dp"

app:layout_anchor="@+id/container"
app:layout_anchorGravity="bottom|center" />

</android.support.design.widget.CoordinatorLayout>

Fragment 布局文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#4FC3F7"
android:orientation="vertical"
android:paddingTop="25dp"
tools:context="net.sarasarasa.lifeup.WelcomeActivity$WelcomeFragment">


<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sample Text"
android:textAlignment="center"
android:textColor="#FFFFFF" />


</LinearLayout>

以下是Java代码部分:

实现自己的 Fragment 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static class WelcomeFragment extends Fragment {

private static final String ARG_SECTION_NUMBER = "section_number";
View rootView;

public WelcomeFragment() {
}


public static WelcomeFragment newInstance(int sectionNumber) {
WelcomeFragment fragment = new WelcomeFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

LottieAnimationView animationViews = null;

switch (getArguments().getInt(ARG_SECTION_NUMBER)) {
case 1:
rootView = inflater.inflate(R.layout.fragment_welcome_page1, container, false);
animationViews = (LottieAnimationView) rootView.findViewById(R.id.animation_view);
animationViews.setAnimation(R.raw.done, LottieAnimationView.CacheStrategy.None);
break;
case 2:
rootView = inflater.inflate(R.layout.fragment_welcome_page2, container, false);
...
//此处根据你的页数需求,可以加载不同的Fragment
}

return rootView;
}

}

实现 FragmentPagerAdapter :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private Fragment mCurrentPrimaryItem;

public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int position) {
return WelcomeFragment.newInstance(position + 1);
}

@Override
public int getCount() {
return PAGE_NUMBER;
//PAGE_NUMBER是声明的常量4,这里返回具体的页数即可。
}

}

然后在 Activity 的 onCreate 方法中加入:

1
2
3
4
5
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setOffscreenPageLimit(0);
mViewPager.setAdapter(mSectionsPagerAdapter);


沉浸式状态栏

经过观察可以发现我们这样写布局,最上层就是 Fragment 。

只是将状态栏设成固定颜色的时候是行不通的,因为我们的多个页面不同颜色,滑动的时候状态栏颜色会是单独一块。

当然,解决办法很简单,只要将状态栏隐藏就可以了。

而且,我们不需要 ActionBar。

在 style.xml 中加入:

1
2
3
4
5
6
7
8
9
10
    <style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.TranslucentTheme" parent="AppTheme.NoActionBar">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>

我们在这里新建一个 theme ,并且让他继承自 NoActionBar,然后设置状态栏为透明。

这样会出现一个小问题:

整个布局的内容会向上移动顶到状态栏。

我们只需要在最上层布局元素加一个 android:paddingTop="25dp"即可。


页面指示器框架

指的是下面的小圆点,指示当前页面。

Google 的库中没有提供直接的实现,

如果自己弄的话要控制每个圆点的大小颜色也挺繁琐的。

所以,第一步当然是找一找有没有现成的轮子。

我们使用的是一个轻量级的框架CircleIndicator

使用方法也很简单:

  1. 首先添加 Gradle 依赖

    1
    2
    3
    dependencies {
    compile 'me.relex:circleindicator:1.2.2@aar'
    }
  2. activity_welcome.xml 布局中添加:

    1
    2
    3
    4
    5
    6
    7
    8
    <me.relex.circleindicator.CircleIndicator
    android:id="@+id/indicator"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:layout_marginBottom="32dp"

    app:layout_anchor="@+id/container"
    app:layout_anchorGravity="bottom|center" />
  3. 修改一下onCreate方法内的关于ViewPager的代码:

    1
    2
    3
    4
    mViewPager = (ViewPager) findViewById(R.id.container);
    CircleIndicator indicator = (CircleIndicator) findViewById(R.id.indicator);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    indicator.setViewPager(mViewPager); //这句一定要在viewPager设置Adapter写


使用 Lottie 框架显示动画

Lottie 是 Airbnb 出的一个开源动画框架,一个动画 json 文件就能在跨平台播放。

  1. 首先,添加Gradle依赖

    1
    2
    3
    dependencies {
    implementation 'com.airbnb.android:lottie:2.5.4'
    }
  2. 这个依赖内间接依赖了, compile 'com.android.support:support-v4:27.1.1'

    所以可能存在依赖冲突问题。可以统一版本来解决。

    或是参考解决android gradle依赖中的冲突

  3. 查阅官方文档,尝试添加动画。

    最简单的使用方式就是将动画 json 文件放入 res/raw 中,然后在布局文件加入以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <com.airbnb.lottie.LottieAnimationView
    android:id="@+id/animation_view"
    android:layout_width="350dp"
    android:layout_height="350dp"
    android:layout_gravity="center"
    android:layout_marginTop="35dp"

    android:paddingStart="50dp"
    app:lottie_autoPlay="false"
    app:lottie_loop="true"
    app:lottie_rawRes="@raw/done" />

    这里以放入的 json 文件名为 done.json 为例。

那么还有一个问题,动画 json 文件哪里来呢?

  1. 可以用 AE 自己制作。
  2. 该网站上有开源供免费使用的 json 文件。

如果想要简单的修改颜色,可以用到 lottie-editor


ViewPager 的简单优化

我们直接这样使用动画会发现会严重掉帧,特别是中间的页面。

这是因为 ViewPager 会自动缓存旁边的页面,并且动画一直在播放(?)。

我们这里做一些简单的优化操作:

  1. 在 Activity 声明 private WelcomeFragment arrWelcomeFragment[];,并且在 onCreate() 的时候保存下来。不用每次都new一个。同时在适配器里重写destroyItem(ViewGroup container, int position, Object object)方法,然后在里面什么都不做,让其不会再自动销毁。

  2. 用代码的时候载入动画,同时将缓存策略设为 None。

    1
    2
    3
    View rootView = inflater.inflate(arrFragment[iPage], container, false);
    animationViews = rootView.findViewById(R.id.animation_view);
    animationViews.setAnimation(arrAnimation[iPage], LottieAnimationView.CacheStrategy.None);
  3. 改变播放策略,在转到该页再从零开始播放动画。

    将所有LottieAnimationView设为app:lottie_autoPlay="false"

    在 Fragment 类中重写setUserVisibleHint(boolean isVisibleToUser)方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**
    * 通过 Fargment 的可见性控制动画的播放与暂停
    *
    * @param isVisibleToUser
    */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    LottieAnimationView animationView = null;

    if (rootView != null) {
    animationView = rootView.findViewById(R.id.animation_view);
    }

    if (animationView != null) {
    if (isVisibleToUser && isCreate) {
    //相当于onResume
    animationView.playAnimation();
    } else {
    //相当于onPause
    animationView.cancelAnimation();
    animationView.setFrame(0);
    }
    }

    }

    这里存在一个小问题,第一个 Fragment 在创建后不会调用这个方法。

    所以第一个 Fragment 要在 onCreateView 的时候,就让她开始播放。


ViewPager 背景色渐变

渐变效果的实现主要参考了别人的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//ViewPager添加onPageChangeListener,实现颜色渐变效果
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
* ViewPager滑动回调方法
* @param position 页签[0 ~ 3]
* @param positionOffset 页百分比偏移[0F ~ 1F]
* @param positionOffsetPixels 页像素偏移[0 ~ ViewPager的宽度]
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
ArgbEvaluator evaluator = new ArgbEvaluator(); // ARGB求值器
int evaluate = 0x00FFFFFF; // 初始默认颜色(透明白)
if (position == 0) {
evaluate = (Integer) evaluator.evaluate(positionOffset, 0XFF4FC3F7, 0XFFE4542F); // 根据positionOffset和第0页~第1页的颜色转换范围取颜色值
} else if (position == 1) {
evaluate = (Integer) evaluator.evaluate(positionOffset, 0XFFE4542F, 0XFF9575CD); // 根据positionOffset和第1页~第2页的颜色转换范围取颜色值
} else if (position == 2) {
evaluate = (Integer) evaluator.evaluate(positionOffset, 0XFF9575CD, 0XFFFFFFFF); // 根据positionOffset和第2页~第3页的颜色转换范围取颜色值
} else {
evaluate = 0XFFFFFFFF; // 最终第3页的颜色
}

//找到Fargment元素设置背景色
for (int i = 0; i < PAGE_NUMBER; i++) {
if (arrWelcomeFragment[i] != null && arrWelcomeFragment[i].getView() != null) {
arrWelcomeFragment[i].getView().setBackgroundColor(evaluate);
}
}
}

@Override
public void onPageSelected(int position) {

}

@Override
public void onPageScrollStateChanged(int state) {

}
});


Android Studio 录制手机屏幕

一直没注意到 AS 有录制屏幕的功能,这次打算做 gif 的时候用到了。

搜索了一下说是在下方的 Monitor,但是找了半天没找到。

原来是改名为 Logcat 了。

具体位置在这里:


Push 到 Github 时遇到的小问题解决

一开始配置完 Git 和 Github 之后,发现 push 会失败。

这时候要去 SettingGit SSH executable 设为 Native

就解决了。


部分参考

推荐4个Android引导页框架

解决android gradle依赖中的冲突

Android - ViewPager进阶篇之渐变背景色

ViewPager使用详解(二):FragmentPagerAdapter

人升开发日志#2 | 6/7 引导页

http://sarasarasa.net/post/17b01d24.html

作者

AyagiKei

发布于

2018-06-07

更新于

2021-08-10

许可协议

评论