Android 仿Boss直聘跳轉(zhuǎn)效果

寫在前面

這段時間由于找工作的原因,下載了boss直聘,在ios最新版(4.1)上點擊首頁列表進行頁面跳轉(zhuǎn)的那個效果感覺很炫,但是android最新版本(4.2)上卻沒有對應(yīng)的效果,不知道以前版本有沒有,感覺很好奇,所以就有了本文...

IOS版本boss直聘的效果

這里寫圖片描述

分析

通過多次觀察頁面跳轉(zhuǎn)動畫,發(fā)現(xiàn)其實現(xiàn)過程也很簡單:</br>
1、獲取列表中item的位置。</br>
2、把根布局縮放0.9倍,同時跳出懸浮框,添加一個View(暫且稱它為tempView),設(shè)置tempView的高度和寬度為列表的item的高度和寬度。</br>
3、對tempView進行縮放,縮放倍數(shù)為tempView距離屏幕頂部,距離屏幕底部中的最大值處于tempView高度: Math.max(tempView.locationX, Math.abs(tempView.locationX - ScreenHeight)) / tempView.height。</br>
4、在安卓上,即使設(shè)置

Intent.FLAG_ACTIVITY_NO_ANIMATION

在部分機型上也無法禁止動畫,如果按照正常的步驟,關(guān)閉懸浮框再進行頁面跳轉(zhuǎn),就達不到boss直聘上的跳轉(zhuǎn)效果,所以就需要當(dāng)tempView展開到最大時,馬上進行頁面跳轉(zhuǎn)。</br>
5、啟動加載等待動畫,延時1秒后,啟動alpha動畫,將tempView透明度設(shè)置為0,關(guān)閉懸浮框。</br>

懸浮框代碼

public class BossTransferView extends LinearLayout {
    private static final String TAG = "ExpansionTemp";
    private View mHandleView;
    private WindowManager mWm;
    private ImageView mImg;
    private View mTemp;
    private ImageView mPb;
    private int[] mLocation = new int[2];
    private View mRootView;

    public BossTransferView(Context context, View rootView, View handleView, WindowManager wm) {
        super(context, null);
        mHandleView = handleView;
        mRootView = rootView;
        mWm = wm;
        init();
    }

    public BossTransferView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
    }

    public BossTransferView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        LayoutInflater.from(getContext()).inflate(R.layout.layout_boss_transfer, this);
        mImg = (ImageView) findViewById(R.id.img);
        mTemp = findViewById(R.id.line);
//        mPb = (ProgressBar) findViewById(R.id.progress);
        mPb = (ImageView) findViewById(R.id.progress);
        mHandleView.getLocationInWindow(mLocation);
        int sbh = Util.getStatusBarHeight(getContext());
        mImg.setTranslationY(mLocation[1] - sbh);
        mTemp.setTranslationY(mLocation[1] + mImg.getMeasuredHeight() / 2 + sbh);
        mPb.setVisibility(GONE);
        Bitmap bm = getViewImg(mHandleView);
        if (bm != null) {
            mImg.setImageBitmap(getViewImg(mHandleView));
        }
        AnimationDrawable ad = new AnimationDrawable();
        ad.addFrame(getDrawable(R.mipmap.icon_refresh_left), 200);
        ad.addFrame(getDrawable(R.mipmap.icon_refresh_center), 200);
        ad.addFrame(getDrawable(R.mipmap.icon_refresh_right), 200);
        mPb.setImageDrawable(ad);
        ad.setOneShot(false);
        ad.start();
    }

    private Drawable getDrawable(@DrawableRes int drawable){
        return getContext().getResources().getDrawable(drawable);
    }

    public void show() {
        handleRootView();
        setBackgroundColor(Color.parseColor("#7f000000"));
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mTemp.setVisibility(View.VISIBLE);
                expansion();
            }
        }, 500);
    }

    private void handleRootView() {
        ObjectAnimator setScaleY = ObjectAnimator.ofFloat(mRootView, "scaleY", 1f, 0.95f);
        ObjectAnimator setScaleX = ObjectAnimator.ofFloat(mRootView, "scaleX", 1f, 0.95f);
        AnimatorSet set = new AnimatorSet();
        set.play(setScaleX).with(setScaleY);
        set.setDuration(500);
        set.start();
    }

    public Bitmap getViewImg(View view) {
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        int width = Util.getScreenParams(getContext())[0];
        Bitmap bmp = view.getDrawingCache();
        if (bmp == null) {
            return null;
        }
        Bitmap bp;
        bp = Bitmap.createBitmap(bmp, 0, 0, width, bmp.getHeight());
        view.destroyDrawingCache();
        return bp;
    }

    /**
     * 擴展到整個屏幕
     */
    private void expansion() {
        int wh = Util.getScreenParams(getContext())[1];
        int sbh = Util.getStatusBarHeight(getContext());
        int h = Math.max(mLocation[1], Math.abs(mLocation[1] - wh));
        ObjectAnimator animator = ObjectAnimator.ofFloat(mTemp, "scaleY", 1f, h + sbh);
        animator.setDuration(500);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mImg.setVisibility(View.GONE);
                Intent intent = new Intent(getContext(), BossDetailActivity.class);
                getContext().startActivity(intent);
                mRootView.setScaleY(1f);
                mRootView.setScaleX(1f);
                mPb.setVisibility(VISIBLE);
                setBackgroundColor(Color.TRANSPARENT);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        fade();
                    }
                }, 1000);
            }
        });
        animator.start();
    }

    /**
     * 淡出
     */
    private void fade() {
        mPb.setVisibility(GONE);
        ObjectAnimator animator = ObjectAnimator.ofFloat(mTemp, "alpha", 1f, 0f);
        animator.setDuration(800);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mTemp.setVisibility(GONE);
//                mTemp.setScaleY(1f);
                mPb.setVisibility(GONE);
                mWm.removeView(BossTransferView.this);
            }
        });
        animator.start();
    }
}

由于涉及到兩個Activity間的跳轉(zhuǎn),所以懸浮框就需要一直處于最顯示層的最頂層,并且該懸浮框需要全局通用。</br>
在andorid里面可以使用WindowManager配合自定義View來實現(xiàn)懸浮框功能,上面便是懸浮框的自定義View。</br>
上面的核心參數(shù)是:mLocation,該數(shù)組是item在屏幕上的位置,通過

view.getLocationInWindow(mLocation);

方法,便可以輕松得到一個View在屏幕上的位置,不同于boss直聘上tempView的空白展開的是,我這里使用了item的圖像緩存代替了boss直聘上tempView的位置,而填充整個頁面任務(wù)是由tempView處于中間位置的一個1dp高度的view進行展開,進而覆蓋整個屏幕。</br>
當(dāng)展開到最大屏幕時,進行頁面跳轉(zhuǎn),并將加載動畫顯示出來,將動畫加載一秒,進行淡出操作,最終,將自定義的懸浮框View從WindowManager移除</br>

跳轉(zhuǎn)類

由于一個工程項目中不可能只有一個列表,因此需要創(chuàng)建一個跳轉(zhuǎn)幫助類,來實現(xiàn)跳轉(zhuǎn)

public class TurnHelp {
    /**
     * 帶動畫跳轉(zhuǎn)詳情頁面
     */
    public static void turn(Context context, View rootView, View itemView) {
        WindowManager wm = (WindowManager) context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams wmParams;
        BossTransferView temp = new BossTransferView(context, rootView, itemView, wm);
        wmParams = new WindowManager.LayoutParams();
//感謝5樓的小伙伴提出的解決小米等機型默認(rèn)禁止彈出懸浮框的方案,直接把type,改為toast就可以了
        wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;     // 系統(tǒng)提示類型,重要
        wmParams.format = 1;
        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 不能搶占聚焦點
        wmParams.flags = wmParams.flags | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
        wmParams.flags = wmParams.flags | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; // 排版不受限制
        wmParams.flags = wmParams.flags | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; // 排版不受限制
        wmParams.alpha = 1.0f;
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;   //調(diào)整懸浮窗口至左上角
        //以屏幕左上角為原點,設(shè)置x、y初始值
        wmParams.x = 0;
        wmParams.y = 0;
        //設(shè)置懸浮窗口長寬數(shù)據(jù)
        wmParams.width = WindowManager.LayoutParams.MATCH_PARENT;
        wmParams.height = WindowManager.LayoutParams.MATCH_PARENT;
        //顯示myFloatView圖像
        wm.addView(temp, wmParams);
        temp.show();
    }
}

上面沒啥好說的,就是WindowManager添加View的基本操作

啟動代碼

private View  mItemView;
mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
          mItemView = view;
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                  && checkSelfPermission(Settings.ACTION_MANAGE_OVERLAY_PERMISSION) == PackageManager.PERMISSION_GRANTED) {
              requestAlertWindowPermission();
          } else {
              TurnHelp.turn(MainActivity.this, findViewById(android.R.id.content), view);
          }

      }
  });

/**
* 6.0申請懸浮框權(quán)限
*/
private void requestAlertWindowPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, 1);
    }
}

/**
* 6.0權(quán)限 回調(diào)
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   super.onActivityResult(requestCode, resultCode, data);
   if (requestCode == 1 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       if (Settings.canDrawOverlays(this)) {
           TurnHelp.turn(MainActivity.this, findViewById(android.R.id.content), mItemView);
       } else {
           Toast.makeText(this, "申請懸浮框權(quán)限失敗", Toast.LENGTH_SHORT).show();
       }
   }
}  

最終效果

這里寫圖片描述

DEMO點我

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

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,761評論 25 708
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 46,868評論 22 665
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,177評論 4 61
  • 女兒的語文作業(yè)是一張試卷,大家都知道的,試卷最后一題就是一篇作文。這張試卷的作文題目是《我的世界真精彩》 女兒對于...
    走向陽光的自己閱讀 581評論 6 6
  • 1、轉(zhuǎn)馬類游樂場設(shè)備的外觀必須擁有色彩鮮艷的外觀,明亮而豐富的燈光和美妙的音樂。眾所周知,第一印象對客戶或乘坐者的...
    金寶客服王慶科閱讀 331評論 0 0