延遲共享元素的過渡動畫 (part 3b)

延遲共享元素的過渡動畫 (part 3b)

通過討論 Lollipop Transition API 的一個重要的特性:延遲共享元素的過渡動畫岩齿,這篇博文將繼續(xù)我們關(guān)于共享元素 Transition 的深度解析卷哩。這也是我關(guān)于 Transition 這個專欄的第四篇文章。

我們通過一個常見的問題來解釋為什么需要推遲某些共享元素的過渡動畫。

理解問題

通常問題的根源是框架在 Activity 生命周期非常早的時候啟動共享元素 Transition 值骇。回想我們的第一篇文章,Transitions 必須捕獲目標 View 的起始和結(jié)束狀態(tài)來構(gòu)建合適的動畫。因此拧廊,如果框架在共享元素獲得它在調(diào)用它的 Activity 中所給定的大小和位置前啟動共享元素的過渡動畫,這個 Transition 將不能正確捕獲到共享元素的結(jié)束狀態(tài)值,生成動畫也會失敗(一個過渡失敗的例子Video 3.3).

Transition 開始前晋修,能否計算出正確的共享元素的結(jié)束值主要依靠兩個因素:

(1) 調(diào)用共享元素的 Activity 的布局復雜度以及布局層次結(jié)構(gòu)的深度
(2)調(diào)用共享元素Activity載入數(shù)據(jù)消耗的時間

布局越復雜吧碾,在屏幕上確定共享元素的大小位置耗時越長。同樣墓卦,如果調(diào)用共享元素的 Activity 依賴一個異步的數(shù)據(jù)載入倦春,框架仍有可能會在數(shù)據(jù)載入完成前自動開始共享元素 Transition。下面列出的是你可能遇到的常見問題:

  • 存在于 Activity 托管的 Fragment 中的共享元素FragmentTransactions 在 commit 后并不會被立即執(zhí)行睁本,它們會被安排到主線程中等待執(zhí)行尿庐。因此,如果共享元素存在的 Fragment 的視圖層和FragmentTransaction沒有被及時執(zhí)行呢堰,框架有可能在共享元素被正確測量大小和布局到屏幕前啟動共享元素 Transition抄瑟。<a id="b1" href="#1">(1)</a>

  • 共享元素是一個高分辨率的圖片。給 ImageView 設(shè)置一個超過其初始化邊界的高分辨率圖片暮胧,最終可能會導致在這個視圖層里出現(xiàn)額外的布局傳遞锐借,由此增加在共享元素準備好前就啟動 Transition 的幾率问麸。流行的異步圖片處理庫比如 VolleyPicasso 往衷,也不能可靠的解決這個問題:框架不能預(yù)先了解圖片是要被下載,縮放還是在后臺線程中從磁盤讀取严卖,也不管圖片是否處理完畢就啟動共享元素 Transition席舍。

  • 共享元素依賴于異步的數(shù)據(jù)加載如果共享元素所需的數(shù)據(jù)是通過AsyncTaskAsyncQueryHandler,Loader或者其他類似的東西加載哮笆,在它們獲得在調(diào)用它們的 Activity 的最終數(shù)據(jù)(大小来颤、位置)前,框架就有可能在主線程中啟動 Transition稠肘。

現(xiàn)在你可能會想:如果有辦法能讓暫時延遲 Transition 的使用福铅,直到我們確定了共享元素的確切大小和位置才使用它就好了。幸好 Activity Transitions API<a id="b2" href="#2">(2)</a> 為我們提供了解決方案项阴。

在 Activity 的onCreate()中調(diào)用postponeEnterTransition() 方法來暫時阻止啟動共享元素 Transition滑黔。之后,你需要在共享元素準備好后調(diào)用 startPostponedEnterTransition 來恢復過渡效果环揽。常見的模式是在一個OnPreDrawListener中啟動延時 Transition略荡,它會在共享元素測量和布局完畢后被調(diào)用<a id="b3" href="#3">(3)</a>。



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Postpone the shared element enter transition.
    postponeEnterTransition();

    // TODO: Call the "scheduleStartPostponedTransition()" method
    // below when you know for certain that the shared element is
    // ready for the transition to begin.
}

/**
 * Schedules the shared element transition to be started immediately
 * after the shared element has been measured and laid out within the
 * activity's view hierarchy. Some common places where it might make
 * sense to call this method are:
 *
 * (1) Inside a Fragment's onCreateView() method (if the shared element
 *     lives inside a Fragment hosted by the called Activity).
 *
 * (2) Inside a Picasso Callback object (if you need to wait for Picasso to
 *     asynchronously load/scale a bitmap before the transition can begin).
 *
 * (3) Inside a LoaderCallback's onLoadFinished() method (if the shared
 *     element depends on data queried by a Loader).
 */
private void scheduleStartPostponedTransition(final View sharedElement) {
    sharedElement.getViewTreeObserver().addOnPreDrawListener(
        new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
                startPostponedEnterTransition();
                return true;
            }
        });
}

忽略方法名歉胶,這里還有第二種方法可以延遲共享元素的返回 Transition汛兜,在調(diào)用Activity的onActivityReenter() 方法中延緩返回 Transition<a id="b4" href="#4">(4)</a>

/**
 * Don't forget to call setResult(Activity.RESULT_OK) in the returning
 * activity or else this method won't be called!
 */
@Override
public void onActivityReenter(int resultCode, Intent data) {
    super.onActivityReenter(resultCode, data);

    // Postpone the shared element return transition.
    postponeEnterTransition();

    // TODO: Call the "scheduleStartPostponedTransition()" method
    // above when you know for certain that the shared element is
    // ready for the transition to begin.
}

盡管添加延時可以讓共享元素 Transition 更加流暢準確,但是你也要知道在應(yīng)用中引入共享元素 Transition 的延遲可能會產(chǎn)生一些負面影響:

  • 調(diào)用postponeEnterTransition后不要忘記調(diào)用startPostponedEnterTransition通今。
    忘記調(diào)用startPostponedEnterTransition會讓你的應(yīng)用處于死鎖狀態(tài)粥谬,用戶無法進入下個Activity。
  • 不要將共享元素 Transition 延遲設(shè)置到1s以上辫塌。延遲時間過長會在應(yīng)用中產(chǎn)生不必要的卡頓漏策,影響用戶體驗。

感謝閱讀璃氢!希望這篇文章對你有所幫助哟玷。

<a id="1" href="#b1">1</a>: 當然,許多應(yīng)用通過調(diào)用 FragmentManager#executePendingTransactions() 來避開這個問題,這樣會強制立即執(zhí)行FragmentTransactions而不是異步巢寡。

<a id="2" href="#b2">2</a>: 注意!postponeEnterTransition()startPostponedEnterTransition()只對 Activity Transition起作用喉脖,對Fragment無效。詳細信息可以在這里找到 StackOverflow & Google+

<a id="3" href="#b3">3</a>: 小貼士:你可以先調(diào)用 View#isLayoutRequested() 來確認是否需要調(diào)用 OnPreDrawListener抑月,有必要的話 View#isLaidOut() 在一些情況下也能派上用場

<a id="4" href="#b4">4</a>: 在開發(fā)者選項中啟用不保留 Activity 選項可以方便調(diào)試共享元素返回/重新進入時對應(yīng)過渡動畫的行為树叽,這也可以幫助測試在返回的過渡效果開始之前可能發(fā)生最糟糕的情況( Activity 需要重新構(gòu)造布局加載數(shù)據(jù)...)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谦絮,隨后出現(xiàn)的幾起案子题诵,更是在濱河造成了極大的恐慌,老刑警劉巖层皱,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件性锭,死亡現(xiàn)場離奇詭異,居然都是意外死亡叫胖,警方通過查閱死者的電腦和手機草冈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓮增,“玉大人怎棱,你說我怎么就攤上這事”僚埽” “怎么了拳恋?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長砸捏。 經(jīng)常有香客問我谬运,道長,這世上最難降的妖魔是什么带膜? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任吩谦,我火速辦了婚禮,結(jié)果婚禮上膝藕,老公的妹妹穿的比我還像新娘式廷。我一直安慰自己,他們只是感情好芭挽,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布滑废。 她就那樣靜靜地躺著,像睡著了一般袜爪。 火紅的嫁衣襯著肌膚如雪蠕趁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天辛馆,我揣著相機與錄音俺陋,去河邊找鬼豁延。 笑死,一個胖子當著我的面吹牛腊状,可吹牛的內(nèi)容都是我干的诱咏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼缴挖,長吁一口氣:“原來是場噩夢啊……” “哼袋狞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起映屋,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤苟鸯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棚点,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體早处,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年乙濒,在試婚紗的時候發(fā)現(xiàn)自己被綠了陕赃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卵蛉。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡颁股,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出傻丝,到底是詐尸還是另有隱情甘有,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布葡缰,位于F島的核電站亏掀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏泛释。R本人自食惡果不足惜滤愕,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望怜校。 院中可真熱鬧间影,春花似錦、人聲如沸茄茁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裙顽。三九已至付燥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間愈犹,已是汗流浹背键科。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勋颖。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓梆掸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親牙言。 傳聞我的和親對象是個殘疾皇子酸钦,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容