1. 程式人生 > >深入理解共享元素變換(Shared Element Transition)-上

深入理解共享元素變換(Shared Element Transition)-上

本文將深入分析共享元素變換(shared element transition)以及它在Activity 和Fragment Transitions API中所扮演的角色。這是這Transition系列文章的第三部分:

第三章(本章)將分為兩部分:上著重底層的原理,下著重api的具體實現,比如延遲某些元素變換的重要性以及SharedElementCallbacks的實現。

什麼是共享元素變換?

元素共享式變換(shared element transition)決定了共享的view元素從一個Activity/Fragment 到另一個Activity/Fragment t的切換中是如何動畫變化的。共享元素在被呼叫Activity進入和返回時播放動畫,共享元素在進入和返回時的變換效果通過window和Fragment的如下方法來設定:

進入:

setSharedElementEnterTransition()

設定在B進入時播放的動畫,共享元素以A中的位置作為起始,B中的位置為結束來播放動畫。

返回:

setSharedElementReturnTransition()

設定在B返回A時的動畫,共享元素以B中的位置作為起始,A中的位置為結束來播放動畫。

注意,Activity Transition API 也可以使用 setSharedElementExitTransition() 和setSharedElementReenterTransition()方法分別設定共享元素的exit 和reenter 變換。但是一般來講這是不必要的。如果你想看先關的例子,可以檢視這篇部落格

this blog post.至於為什麼Fragment中沒有共享元素的exit 和reenter 變換,請檢視George Mount在stackoverflow上的回答:this StackOverflow post

8942111.gif

上圖演示了google play music應用中的共享元素變換效果。變換包含了兩個共享的view元素:一個ImageView以及他的父親CardView。ImageView在兩個activity之間無縫的動畫切換,而CardView則是漸漸的擴充套件到介面上。

在第一章中我們簡單的介紹了這個話題,這篇文章則是更深入的去分析共享元素變換(shared element transition)。共享元素變換的原理是什麼?有哪些共享元素變換效果可用?共享元素變換動畫是如何繪製的,又是在哪裡繪製的?接下來的小節中我們將一一回答。

共享元素變換揭祕

從前兩篇文章中我們知道,一個變換(Transition )主要有兩方面的職責:

捕獲view開始和結束狀態以及建立一能在兩個狀態間漸變的動畫。共享元素變換沒有什麼不同。在共享元素變換開始之前,必須首先捕獲每個共享元素的開始和結束狀態(呼叫activity以及被呼叫activity中的位置、大小、外觀),有了這些資訊才能決定每個共享元素的入場動畫。

深入理解Content Transition 中類似,framework的共享元素變換是通過執行時改變其屬性實現的,當Activity A 呼叫 Activity B ,發生的事件流如下:

1.Activity A呼叫startActivity(), Activity B被建立,測量,同時初始化為半透明的視窗和透明的背景顏色。

2.framework重新分配每個共享元素在B中的位置與大小,使其跟A中一模一樣。之後,B的進入變換(enter transition)捕獲到共享元素在B中的初始狀態。

3.framework重新分配每個共享元素在B中的位置與大小,使其跟B中的最終狀態一致。之後,B的進入變換(enter transition)捕獲到共享元素在B中的結束狀態。

4.B的進入變換(enter transition)比較共享元素的初始和結束狀態,同時基於前後狀態的區別建立一個Animator(屬性動畫物件)。

5.framework 命令A隱藏其共享元素,動畫開始執行。隨著動畫的進行,framework 逐漸將B的activity視窗顯示出來,當動畫完成,B的窗口才完全可見。

與內容變換(content transition)取決於view的可見性不同(visibility),共享元素變換取決於每個共享元素的位置、大小以及外觀。在api 21中,框架層提供了幾個Transition 的實現,可以用於定義共享元素在場景中的切換效果。

ChangeBounds -捕獲共享元素的layout bound,然後播放layout bound變化動畫。ChangeBounds 是共享元素變換中用的最多的,因為前後兩個activity中共享元素的大小和位置一般都是不同的。

ChangeTransform -  捕獲共享元素的縮放(scale)與旋轉(rotation)屬性 ,然後播放縮放(scale)與旋轉(rotation)屬性變化動畫。

ChangeClipBounds -  捕獲共享元素clip bounds,然後播放clip bounds變化動畫。

ChangeImageTransform -  捕獲共享元素(ImageView)的transform matrices 屬性,然後播放ImageViewtransform matrices 屬性變化動畫。與ChangeBounds相結合,這個變換可以讓ImageView在動畫中高效實現大小,形狀或者ImageView.ScaleType 屬性平滑過度。

@android:transition/move -  將上述所有變換同時進行的一個TransitionSet 。就如在第一章中所講的一樣,如果共享元素的進入和返回變換沒有特別宣告,框架將使用它作為預設的變換。

我們可以看到,共享元素變換並不是真正實現了兩個activity或者Fragment之間元素的共享,實際上我們看到的幾乎所有變換效果中(不管是B進入還是B返回A),共享元素都是在B中繪製出來的。Framework沒有真正試圖將A中的某個元素傳遞給B,而是採用了不同的方法來達到相同的視覺效果。A傳遞給B的是共享元素的狀態資訊。B利用這些資訊來初始化共享View元素,讓它們的位置、大小、外觀與在A中的時候完全一致。當變換開始的時候,B中除了共享元素之外,所有的其他元素都是不可見的。隨著動畫的進行,framework 逐漸將B的activity視窗顯示出來,當動畫完成,B的窗口才完全可見。

使用共享元素的 Overlay

最後,我們需要討論一下shared element overlay這個概念才算是對共享元素變換的繪製過程有了一個完整的瞭解。

雖然不是非常明顯的可以看到,共享元素預設其實是繪製在整個view樹結構的最上層,在一個叫ViewOverlay的東西上面。你可能沒聽說過ViewOverlay,他是4.3之後才有的一個新類,它是view的最上面的一個透明的層,新增到ViewOverlay上面的Drawable和view可以被繪製到任何東西的上面,甚至是ViewGroup的子元素。這似乎可以解釋為什麼framework 會選擇ViewOverlay來作為共享元素變換的繪製空間了。

雖然共享元素預設是繪製在ViewOverlay上面,但是framework 還是提供了關閉這個選項的功能,呼叫Window的setSharedElementsUseOverlay(false) 方法。這樣主要是為了防止萬一有這樣的開發需要。如果你選擇了關閉overlay,那麼請注意這是有一定副作用的。

568.gif

在上圖的效果中,我們運行了兩次不同方式的動畫,第二次便是關閉overlay之後的效果,我們可以明顯的看到這導致了一個問題。

總之除非有一萬個理由,否則不要關閉shared element overlay。

總結

這篇文章涵蓋了如下幾個要點:

1.元素共享式變換(shared element transition)決定了共享的view元素從一個Activity/Fragment 到另一個Activity/Fragment t的切換中是如何動畫變化的。

2.共享元素變換取決於每個共享元素的位置、大小以及外觀。

3.共享元素預設其實是繪製在整個view樹結構的最上層,在一個叫ViewOverlay的東西上面。

4.共享元素變換並不是真正實現了兩個activity或者Fragment之間元素的共享,Framework採用了不同的方法來達到相同的視覺效果。

注:作者在github上上傳了一個transaction的demo,雖然沒有在文章中明確說明,但我覺得就是這系列文章的相關demo:activity-transitions

相關推薦

深入理解共享元素變換Shared Element Transition-

本文將深入分析共享元素變換(shared element transition)以及它在Activity 和Fragment Transitions API中所扮演的角色。這是這Transition系列文章的第三部分: 第三章(本章)將分為兩部分:上著重底層的原理,下

深入理解Java Lambda表示式全網之最

本文將結合書本和網路教程,闡述自己對於Lambda表示式的理解,如有偏差,歡迎指正... 目錄 方法引用:  技術的進步,循序漸進;慢下來,紮紮實實;用過度的功夫,才能理解表面膚淺的深度 什麼是Lambda表示式? 可以將Lamb

全面深入理解Redis與Memcached深度好文

說到redis就會聯想到memcached,反之亦然。瞭解過兩者的同學有那麼個大致的印象:redis與memcached相比,比僅支援簡單的key-value資料型別,同時還提供list,set,zset,hash等資料結構的儲存;redis支援資料的備份,即master-s

深入理解Java虛擬機器類檔案結構

深入理解Java虛擬機器(類檔案結構) 歡迎關注微信公眾號:BaronTalk,獲取更多精彩好文! 之前在閱讀 ASM 文件時,對於已編譯類的結構、方法描述符、訪問標誌、ACC_PUBLIC、ACC_PRIVATE、各種位元組碼指令等等許多概念聽起來都是雲山霧罩、一知半解,原因就在於對類檔案結構和

深入理解OkHttp源碼——提交請求

mat esp 屬於 idt set ref setname 失敗 class 本篇文章主要介紹OkHttp執行同步和異步請求的大體流程。主要流程如下圖: 主要分析到getResponseWidthInterceptorChain方法,該方法為具體的根據請求獲取響應

深入理解Java:註解Annotation--註解處理器

fault this urn 復制代碼 lena ide set java lec 深入理解Java:註解(Annotation)--註解處理器   如果沒有用來讀取註解的方法和工作,那麽註解也就不會比註釋更有用處了。使用註解的過程中,很重要的一部分就是創建於

深入理解Java的註解Annotation:註解處理器3

isp 通過反射 out peid 擴展 .cn 自定義註解 忽略 否則 如果沒有用來讀取註解的方法和工作,那麽註解也就不會比註釋更有用處了。使用註解的過程中,很重要的一部分就是創建於使用註解處理器。Java SE5擴展了反射機制的API,以幫助程序員快速的構造自定義註解處

深入理解Flink核心技術轉載

優點 流程圖 align 優化器 red 興趣 hdf 定義 lin 作者:李呈祥 Flink項目是大數據處理領域最近冉冉升起的一顆新星,其不同於其他大數據項目的諸多特性吸引了越來越多的人關註Flink項目。本文將深入分析Flink一些關鍵的技術與特性,希望能夠幫助讀者對

javascript深入理解js閉包

erro 對象 anon 無法找到 否則 src 興趣 名稱 如圖所示 javascript深入理解js閉包 轉載 2010-07-03 作者: 我要評論 閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包

深入理解Java虛擬機jvm性能調優+內存模型+虛擬機原理視頻教程

boot operate 小型 spa clas padding ali restful left 14套java精品高級架構課,緩存架構,深入Jvm虛擬機,全文檢索Elasticsearch,Dubbo分布式Restful 服務,並發原理編程,SpringBoot,Sp

深入理解java虛擬機十二 Java 語法糖背後的真相

它的 blog 需要 原來 ont 影響 else 階段 board 語法糖(Syntactic Sugar),也叫糖衣語法,是英國計算機科學家彼得·約翰·蘭達(Peter J. Landin)發明的一個術語。指的是,在計算機語言中添加某種語法,這些語法糖雖然不會對語言的功

深入理解Java虛擬機筆記

包括 指針 思想 創建 區域 算法; 很多 由於 線程安全 內存分配:   為對象分配內存有兩種方式,第一種是“指針碰撞”,也就是把內存分為兩邊,一邊是已使用區域,另一邊是未分配區域,分界線用指針記錄,當要分配內存時,只需把指針向未分配區域移動需要的空間即可,通常compa

深入理解Java虛擬機jvm性能調優+內存模型+虛擬機原理

Java 課程大綱:第1節說在前面的話 00:05:07分鐘第2節整個部分要講的內容說明 00:06:58分鐘第3節環境搭建以及jdk,jre,jvm的關系 00:20:48分鐘第4節jvm初體驗-內存溢出問題的分析與解決 00:17:59分鐘第5節jvm再體驗-jvm可視化監控工具 00

深入理解MyBatis的原理:配置文件

dynamic 如何 turn ready conf 屬性。 支持 left bool 前言:前文提到一個入門的demo,從這裏開始,會了解深入 MyBatis 的配置,本文講解 MyBatis 的配置文件的用法。 目錄 1、properties 元素 2、設置(set

深入理解MyBatis的原理:配置文件用法

pac amt 單個 gis obb rri tab obj 用戶 前言:前文講解了 MyBatis 的配置文件一部分用法,本文將繼續講解 MyBatis 的配置文件的用法。 目錄 1、typeHandler 類型處理器 2、ObjectFactory 3、插件 4、e

深入理解Java虛擬機類文件結構+類加載機制+字節碼執行引擎

本地變量 ber 關鍵字 作者 看書 講解 個數 寫入 class類 周誌明的《深入理解Java虛擬機》很好很強大,閱讀起來頗有點費勁,尤其是當你跟隨作者的思路一直探究下去,開始會讓你弄不清方向,難免有些你說的啥子的感覺。但知識不得不學,於是天天看,反復看,就慢慢的理解了。

深入理解線性迴歸演算法:正則項的詳細分析

前言 當模型的複雜度達到一定程度時,則模型處於過擬合狀態,類似這種意思相信大家看到個很多次了,本文首先討論了怎麼去理解複雜度這一概念,然後回顧貝葉斯思想(原諒我有點囉嗦),並從貝葉斯的角度去理解正則項的含義以及正則項降低模型複雜度的方法,最後總結全文。     &nb

深入理解線性迴歸演算法:淺談貝葉斯線性迴歸

前言 上文介紹了正則化項與貝葉斯的關係,正則化項對應於貝葉斯的先驗分佈,因此通過設定引數的先驗分佈來調節正則化項。本文首先介紹了貝葉斯線性迴歸的相關性質,和正則化引數λ的作用,然後簡單介紹了貝葉斯思想的模型比較,最後總結全文。   目錄 1、後驗引數分佈和預測變數分

深入理解多執行緒—— Moniter的實現原理

在深入理解多執行緒(一)——Synchronized的實現原理中介紹過關於Synchronize的實現原理,無論是同步方法還是同步程式碼塊,無論是ACC_SYNCHRONIZED還是monitorenter、monitorexit都是基於Monitor實現的,那麼這篇來介紹下什麼是Monitor。

深入理解java虛擬機器位元組碼指令簡介

Java虛擬機器指令是由(佔用一個位元組長度、代表某種特定操作含義的數字)操作碼Opcode,以及跟隨在其後的零至多個代表此操作所需引數的稱為運算元 Operands 構成的。由於Java虛擬機器是面向運算元棧而不是暫存器的架構,所以大多數指令都只有操作碼,而沒有運算元。 位元組碼指令集是一種具有鮮明特點、