IndeterminateProgressbar解析-Part 2

IndeterminateProgressbar解析-Part 2

IndeterminateProgressBar 能在用戶進行某項不定時長的耗時操作時提供絕佳的用戶體驗,之前我有教過大家怎么創建水平的 IndeterminateProgressBar,今天我就來教大家實現圓形的 IndeterminateProgressBar,這個控件將支持 API 11(Honeycomb)以上的設備。

在上一篇博文中我們學習了圓形 IndeterminateProgressBar 的 AOSP 實現方式,以及 AnimatedVectorDrawable 如何被用于顯示 VectorDrawable 路徑動畫以得到圓形 IndeterminateProgressBar 的長度變化動畫。在本篇博文中我們將把注意力轉移到插值器上,即研究圓形 IndeterminateProgressBar 在顯示長度變化動畫時,是如何控制圓弧起點和終點的位置的。

不妨直接看 AOSP 的源碼吧,首先看 控制 trimPathStart 的值的插值器:

<?xml version="1.0" encoding="utf-8"?>
<!--
 Copyright (C) 2014 The Android Open Source Project
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
          http://www.apache.org/licenses/LICENSE-2.0
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:pathData="L0.5,0 C 0.7,0 0.6,1 1, 1" />

乍一看這代碼怎么這么少,那個 PathInterpolator 到底是什么鬼?

PathInterpolator 其實就是 Lollipop 中介紹的描述插值器功能最具代表性的插值器子類,看到這里不要絕望,在以后的博文中我們還會遇到 PathInterpolatorCompat 這個類。

A PathInterpolator takes an SVG pathData parameter which describes a mapping function of the form y = f(x). That sounds rather complex, but it is actually much simpler than it sounds. Effectively it is a square canvas which is one unit in each direction from 0,0 to 1,1. The PathInterpolator works by returning the y value for any given x value. The input values range from 0.0-1.0, so there only stipulation is that each possible value for x can only map to a single value of y – the path cannot double back on itself in the horizontal plane in other words.

PathInterpolator 需要 SVG pathData 參數以描述 y = f(x) 的映射關系,可能聽起來有點復雜,但其實它非常簡單。實際上,就是一個每個方向上都有一個從 0,0 到 1,1 的單元的方形畫布,PathInterpolator 可以根據任意給定的 x 的值返回給定函數所映射的 y 值,其接收的輸入的取值范圍是 0.0 - 1.0,所以其輸入的唯一約定就是:每一個可能的 x 和 y 必須是1對1映射。

如果我們畫了一條從 0,0 到 1,1 的直線,實際上就相當于創建了線性插值器(LinearInterpolator),因為每一個 x 的值對應的 y 值都相同。那么上述代碼中 pathData 到底做了什么?運用一個有趣的技巧,我們可以創建 VectorDrawable 并添加該 path 元素,然后用 Android Studio 的預覽功能就會看到下圖:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:width="72dp"
  android:height="72dp"
  android:viewportWidth="1"
  android:viewportHeight="1"
  tools:ignore="UnusedResources">

  <path
    android:strokeColor="#0000FF"
    android:strokeWidth="0.005"
    android:pathData="L0.5,0 C 0.7,0 0.6,1 1, 1" />

<vector>

由圖可知,0,0 就是路徑的左上角,1,1 就是路徑的右下角。當 x = [0.0 - 0.5], y = 0;當 x = (0.5, 1.0],y 值的增長逐漸增加,然后超過中值,增長速率又漸漸變慢,最終為 1.0。其實際作用與 AccelerateDecelerateInterpolator 相同。如果我們研究 trimPathEnd 使用的插值器,會發現這兩個階段完成的工作比使用傳統插值器要復雜:

<?xml version="1.0" encoding="utf-8"?>
<!--
 Copyright (C) 2014 The Android Open Source Project
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at
          http://www.apache.org/licenses/LICENSE-2.0
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:pathData="C0.2,0 0.1,1 0.5, 1 L 1,1" />

看起來這段 xml 代碼和上面的很類似,但 pathData 對應的值是不同的,不妨再次利用 VectorDrawable 將這個插值器對應的函數圖像顯示出來:

圖中紅色顯示作加速的部分,y 值快速增加直到大于中值,然后減緩增大的速率直到值為 1.0,相當于把上面的過程反過來。

trimPathEnd 會控制長度變化動畫中圓弧的終點,trimPathStart 則控制該圓弧的起點。利用這些插值器我們可以讓圓弧的長度自動變化,以顯示長度變化的動畫。最終結合旋轉動畫就可以實現該圓形 IndeterminateProgressbar 的效果,即下面視頻展示的效果:

視頻

現在我們明白該控件是怎么實現的了,而且 AnimatedVectorDrawable 支持 Android 5.0 以前的版本,因此我們不用擔心它的兼容性問題(在寫下本文時 VectorDrawableCompat 由于兼容性的問題不是個好選擇)。因此我們不需要 VectorDrawable 就可以利用到目前為止學習的知識在 API 11 上實現酷炫的動畫效果,在下一篇博文中我將會介紹應該怎么去實現。

因為這篇博文都是基于 Google 源碼進行的,所以我就不提供源碼了,但后面的文章我保證都會有源碼!


所屬標簽

無標簽

25选5玩法中奖