一起擼個微信圖片瀏覽的BaseActivity吧(上)——初步思考與基礎結構

本項目git: https://github.com/razerdp/ZoomViewActivity

【下篇】一起擼個微信圖片瀏覽的BaseActivity吧(下)——過渡動畫的實現

項目預覽圖:

preview.gif

距離上次更新博客有兩三個月了。。。。太懶了orz...

在微信的日常使用中,我們點擊圖片放大的時候都有一個動畫效果,這個動畫效果過渡看起來很自然,在5.0之后,擁有ShareElement之后做到這個還是比較好做的,然而目前在我們的日常開發中,大多數app兼容都是下限為4.0而不是5.0,所以要實現這個動畫效果就需要我們花費一點心思了。

事實上,在朋友圈項目中,我們就實現過這樣的一個圖片瀏覽動畫,詳情點我→《一起擼個朋友圈吧 - 圖片瀏覽(中)【圖片瀏覽器】》

然而在這里的實現按照我目前的看法,是不太完美的,原因有二:

  • 圖片瀏覽視圖跟時間線(timeline)處于同一Activity,即便我將它移到一個代理類里面,但還是顯得依賴性很大。
  • 基于第一點,不便于其他Activity使用

總的來說,就是一個定制性的類,不太符合我們的“通用性”思想。

于是,再稍微整理和封裝之后,我們就有了今天的這個項目。

在說明之前,先聲明一下目前仍然有的不足:

  • 對于圖片的scaleType支持不好
  • 暫時沒有針對多圖瀏覽(ViewPager)做優化

暫且算是幾個issue吧,有空再處理一下。

廢話說完,那么就正式開始我們的項目吧。


【Step 1】思考

在朋友圈項目中,最難的那一部分——即如何做到圖片放大縮小已經是解決了(感謝官方代碼-V-),那么現在我們遇到的難題有兩個:

  • 如何做到順利的過渡到新的Activity中
  • 圖片縮小的時候如何正確的回歸到前一個Activity的小圖中

在朋友圈項目里,我們知道做到這種圖片的由小到大的過渡實際上是一個障眼法,就是大圖一開始不可見并且以小圖的大小開始顯示,并做放大和位移動畫達到一種視覺上看起來像是從小圖放大的感覺。

而這兩者的實際核心在于得到View的繪制區域,也就是getGlobalVisibleRect()方法,在朋友圈項目里,我把大圖和時間線放到同一個Activity的原因就是因為即使View不可見,但只要執行到resume后,就可以拿到繪制區域。

但如果放到一個新的Activity里,我們就沒法這么做了,因為在onCreate()里面,我們并無法拿到View的屬性信息,也就拿不到繪制區域了。

然而當初做點擊展開控件的時候(鏈接→)《一起擼個朋友圈吧(step5) - 控件篇【點擊展開】》 我講述過TextView的onPreDraw()方法,那時候我留意到TextView實現了OnPreDrawListener,便以為只有某些View實現了這個方法,其他View使用的話是無效的,直到最近查閱了View的資料之后,才發現其實無論是什么View,都會在ViewRootImpl的performTraversals()方法里檢測onPreDraw(cancelDraw),而在執行這個方法之前,實際上已經是measure過了,所以這個方法對于任何View都是有效的。

有了這一點,我們就可以解決上面的問題了,在onPreDraw里面得到繪制區域,然后計算比率之后進行動畫的展開就可以實現進入Activity的時候開展動畫。

回到我們的第一個問題,解決了動畫播放之后,我們還要解決的是如何打開窗口的時候不進行動畫,關于這一點是在再簡單不過了,我們只需要startActivity后執行overridePendingTransition(0, 0);就可以禁用窗口切換動畫了。

至此,我們第一個問題解決的思路如下:

  • 目標ImageView實現onPreDrawListener,并在里面獲取getGlobalVisibleRect。
  • startActivity禁用動畫(特指位移動畫,實際上Alpha動畫還是可以接受的),使用戶的焦點集中在圖片中而不集中在Activity過場動畫中。

然后第二個問題,在朋友圈項目中也講解過,在view點擊的時候就把view的rect傳過來,最后執行退出動畫時回歸原來的位置即可。


【Step 2】封裝

如題,我們的標題名字叫做BaseActivity,因此我們的目的很簡單,就是讓子類輕松實現這個效果,并且可以更好的拓展,而不要說只能是固定的一個Activity。

因此我們的BaseActivity需要實現以下幾個功能:

  • 得到目標View,即最終放大的View
  • 播放進場動畫/退場動畫
  • 實現核心算法,并保證私有,對內保護
  • 判斷是否進行動畫

綜上所述,我們暫時可以寫出如下的代碼結構:

public abstract class BaseScaleElementAnimaActivity<V extends ImageView> extends AppCompatActivity {

    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //數據初始化
        initData();
    }

    @Override public void setContentView(@LayoutRes int layoutResID) {
        super.setContentView(layoutResID);
        //針對目標View的初始化
        initImageView();
    }

    private void initData() {

    }

    private void initImageView() {
        
    }

    //進場過渡動畫(放大)
    private void playEnterAnima() {
      
    }

    //退場過渡動畫(縮小)
    private void playExitAnima() {
      
    }

    @Override public void finish() {
        super.finish();
        overridePendingTransition(0, android.R.anim.fade_out);
    }

    //子類限制
    protected abstract V getAnimaedImageView();
    //子類限制(此處用的Glide)
    protected abstract void onLoadingPicture(SimpleTarget targetImageView, String url);
    //放大/縮小比例計算
    private float[] calculateRatios(Rect startBounds, Rect finalBounds) {
      
    }
    //startActivity方法
    public static void startWithScaleElementActivity(Activity from,
                                                     @Nullable String picUrl,
                                                     @Nullable Rect fromRect,
                                                     Class<? extends BaseScaleElementAnimaActivity> clazz) {
        Intent intent = new Intent(from, clazz);
        intent.putExtra("url", picUrl);
        intent.putExtra("fromRect", fromRect);
        from.startActivity(intent);
        //禁用過渡動畫
        from.overridePendingTransition(0, 0);
    }
}

對于子類而言,它并不需要知道如何實現放大/縮小動畫,它只需要提供最終展示的View和在什么時候載入圖片的時機(本項目采用Glide,其他圖片框架請自行替換設計)。

所以在父類的onCreate中,我們需要拿到前一個Activity點擊的View的繪制區域以及圖片url,在setContentView中,我們需要子類提供目標View,其余操作都放在父類執行。

在使用該功能的Activity時必須采用對應的靜態方法,畢竟咱們有點特殊是吧。。。

【第一章節完,下一章開始實現動畫】

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容