實現Activity間的共享控件轉場動畫

yan_open 8年前發布 | 26K 次閱讀 Activity Android開發 移動開發

原文出處: http://www.jianshu.com/p/841f7b95ca77

Lollipop中有shared_element可以進行元素在activity之間進行共享,網上已經有很多介紹了,然而目前還有大量的kitkat設備,所以說啊,兼容更重要。

如下的方法,可以實現在舊的手機上實現動畫效果。采用了類似于豌豆莢的開眼項目使用的技術.

Preview

實現原理

最近逛業界良心酷安網,發現了豌豆莢的一款叫做 開眼 的項目,這個項目的意義就是每天把墻外的東西搬運回來讓村里的阿Q們開開眼,這款app至少目前看還沒有那么毒瘤,還是比較小而美的,于是下載試用了一下。

有個轉場動畫使用了類似上面gif的效果,第一感覺是自定義了一個popwindow,于是起床,打開電腦,對兩個效果的始末進行查詢

# grep 是 unix命令,windows下先進shell再輸入dump...內容
adb shell dumpsys window windows | grep -E 'mCurrentFocus'

結果如下,可以發現是2個activity,而不是自定義view實現的

mCurrentFocus=xx/com.wandoujia.eyepetizer.ui.activity.FeedActivity}
mCurrentFocus=xx/com.wandoujia.eyepetizer.ui.activity.DetailActivity}

反復研究,最后發現原理如下

  1. FeedActivity將view的top/width/height,內容等信息通過intent進行發送

  2. DetailActivity設置為背景透明模式,轉場動畫關閉,這里關閉是非常重要的

  3. DetailActivity接著讀取intent,并根據高度等信息進行動畫繪制,由于DetailActivity的背景是透明的,所以用戶會誤認為是進行了“放大”操作

在UED中,“放大”與“右轉”是兩種常見的場景切換操作,安利一個叫做《Learn iOS Design》的書,Android開發者也值得借鑒一下

步驟

步驟非常簡單,主要時間是耗在了調試動畫上

1. 設置DetailActivity的主題

<style name="DetailedTheme" parent="AppTheme">
  <!--背景透明-->
  <item name="android:windowIsTranslucent">true</item>
  <item name="android:windowBackground">@android:color/transparent</item>
  <!--無進入動畫-->
  <item name="android:windowAnimationStyle">@null</item>
</style>

2. 獲取FeedActivity中的itemview

樓主在RecyclerView的Adapter中的viewholder中手動加了一個接口,在主界面實現

@Override public void onItemClick(View v, int position) {
  Parcelable imgInfo = ((CardAdapter) mRecyclerView.getAdapter()).getData().get(position);
  int top = v.getTop();
  int heigh = v.getHeight();
  int width = v.getWidth();
  //發送Intent Extra
  DetailedActivity.startActivity(v.getContext(), imgInfo, top, heigh, width);
}

3. 在DetailActivity中進行動畫

動畫沒有什么技巧,跟老司機開車一樣,屬于熟練工種,我們這里主要是使用了AnimationSet進行并發動畫

void anim(View view, int top, int height, int width, boolean isEnter,
    Animation.AnimationListener listener) {
    //記住括號哦,我這里調試了一小時
  float delta = ((float) width) / ((float) height);
  float fromDelta, toDelta, fromY, toY;
  if (isEnter) {
    fromDelta = 1f;
    toDelta = delta;
    fromY = top;
    toY = 0;
  } else {
    fromDelta = delta;
    toDelta = 1f;
    fromY = 0;
    toY = top;
  }
  Animation anim = new ScaleAnimation(fromDelta, toDelta,
      // Start and end values for the X axis scaling
      fromDelta, toDelta, // Start and end values for the Y axis scaling
      Animation.RELATIVE_TO_SELF, 0.5f, // scale from mid of x
      Animation.RELATIVE_TO_SELF, 0f); // scale from start of y
  Animation trans = new TranslateAnimation(0, 0f, fromY, toY);
  AnimationSet set = new AnimationSet(true);
  //添加并行動畫
  set.addAnimation(anim);
  set.addAnimation(trans);
  //動畫結束后保持原樣
  set.setFillEnabled(true);
  set.setFillAfter(true);
  //監聽器
  set.setAnimationListener(listener);
  set.setDuration(AnimateUtils.ANIM_DORITION);
  view.startAnimation(set);
}

這樣,動畫就搞定了,是不是很簡單?

總結

源碼仍在更新中,后期可能將加入大量仿iOS的組件

https://github.com/miao1007/Lollipop-Animation-Sample

最后,總結一下,這個東西實現不難,但是

  1. 調試動畫太費時間了,暗坑多

  2. 大部分手機fps運行狀態未知

  3. 編碼改動量大,很難把所有業務封裝在一個文件中,源碼亂,后期維護困難

所以除了情懷,很少有專門的人愿意這樣寫,我建議在個人app中使用,或者提起商量好了再合作編碼。另外關于狀態欄適配,可以參考 這里

謝謝大家的觀看,如果覺得本文有意義的話,不妨點個贊或者分享吧!

 本文由用戶 yan_open 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!