自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

酷炫的Android交互動(dòng)畫和視覺效果:高仿音悅臺(tái)播放頁面

移動(dòng)開發(fā) Android
新版的音悅臺(tái) APP 播放頁面交互非常有意思,可以把播放器往下拖動(dòng),這個(gè)頁面透明漸變,然后到底部可以左右拖動(dòng)關(guān)閉播放器,然后點(diǎn)擊視頻列表有個(gè)頁面彈出來的效果,十分炫酷,于是我自己動(dòng)手實(shí)現(xiàn)了這個(gè)交互炫酷的播放器頁面。

新版的音悅臺(tái) APP 播放頁面交互非常有意思,可以把播放器往下拖動(dòng),這個(gè)頁面透明漸變,然后到底部可以左右拖動(dòng)關(guān)閉播放器,然后點(diǎn)擊視頻列表有個(gè)頁面彈出來的效果,十分炫酷,于是我自己動(dòng)手實(shí)現(xiàn)了這個(gè)交互炫酷的播放器頁面。

[[181643]]

1.廢話不多說,直接演示實(shí)現(xiàn)效果

1.1.點(diǎn)擊某個(gè)視頻,然后手指上下拖動(dòng),播放器做尺寸比例的漸變,視頻相關(guān)信息做透明度漸變

 

 

 

 

1.2.播放器只有在底部的時(shí)候,才能左右拖動(dòng),此時(shí)播放器做透明度漸變,拖動(dòng)一定范圍可以關(guān)閉播放器;然后它只有在原始位置的一小段距離內(nèi)可以往上拖動(dòng)

 

 

 

 

1.3.點(diǎn)擊視頻列表的時(shí)候,若是上次視頻是左右拖動(dòng)關(guān)閉的話,會(huì)有個(gè)彈起播放頁面的效果;若是返回鍵和返回箭頭則無效果

 

 

 

 

2.實(shí)現(xiàn)的思路講解

毫無疑問,需要自定義一個(gè)容器,然后處理它的觸摸事件,對它的子 View 進(jìn)行不同的處理。觸摸事件的處理使用 ViewDragHelper 是再適合不過了,然后你需要實(shí)現(xiàn)容器 onMeasure 和 onLayout,由于使用了 ViewDragHelper,有些坑在代碼解析的時(shí)候就會(huì)講解。

播放頁面是用新的 Activity 還僅僅是當(dāng)前 Activity 的View的問題,由于播放器縮小到底部的時(shí)候,用戶是可以滑動(dòng)視頻列表的,所以我個(gè)人認(rèn)為就是在當(dāng)前 Activity 放置一個(gè)自定義容器即可,因此為了效率考慮你可以用 ViewStub 來懶加載處理,這里方便演示我就直接 View 的形式了。

3.代碼解析

3.1.需要的變量

 

 

 

 

3.2.初始化做 ViewDragHelper 的初始化,然后 post 拿到兩個(gè)子 View,這里強(qiáng)制規(guī)定只能有兩個(gè)子元素

 

 

 

 

3.3. ViewDragHelper 的回調(diào)需要做的事情比較多,在 mFlexView 拖動(dòng)的時(shí)候需要同時(shí)設(shè)置 mFlexView 和 mFollowView 的相應(yīng)變化效果,在 mFlexView 釋放的時(shí)候需要處理關(guān)閉或收起等效果

 

 

 

 

3.4.接下來是處理測量和定位,我們實(shí)現(xiàn)的排列效果類似 LinearLayout 垂直排列的效果,這里被 measureChildWithMargins 的 heightUse 擺了一道;onLayout 的時(shí)候在位置緩存不為空的時(shí)候直接定位是因?yàn)?ViewDragHelper 在處理觸摸事件子元素在做一些平移之類的,若是有元素更新了 UI 會(huì)導(dǎo)致重新 Layout,例如我的播放器在更新時(shí)間的 TextView 時(shí)就會(huì)如此,因此在 FlexCallback 的 onViewPositionChanged 方法記錄位置,在重新 Layout 時(shí)恢復(fù)位置即可,這個(gè)也坑了好久

 

 

 

 

3.5.觸摸事件的處理,由于縮放不會(huì)影響 mFlexView 真實(shí)寬高,ViewDragHelper 仍然會(huì)阻斷 mFlexView 的真實(shí)寬高的區(qū)域,所以這里判斷手指是否落在 mFlexView 視覺上的范圍內(nèi),在才去調(diào) ViewDragHelper 的 shouldInterceptTouchEvent 方法

 

 

 

 

3.6.在 computeScroll 中,若是 mIsClosing 為 true,即關(guān)閉的整個(gè)平移執(zhí)行完畢了,通知回調(diào)事件

 

 

 

 

3.7.容器實(shí)現(xiàn)了,接下來我們繼承 YytLayout 實(shí)現(xiàn)播放器頁面的組合控件即可,再封裝一些常用的方法,這里使用的是大名鼎鼎的 Ijkplayer 實(shí)現(xiàn)的播放器,屏蔽了 IjkVideoView 的觸摸事件自己處理了;順帶一提,為了實(shí)現(xiàn)播放器 Controller 跟隨拖動(dòng)縮放的效果,放棄了常用的 PopupWindow 實(shí)現(xiàn)的思路,IjkController 直接是添加到 IjkVideoView 中的,要不彈窗實(shí)現(xiàn)跟隨播放器太麻煩了

  1. /** 
  2.  * Created by Oubowu on 2016/12/27 17:32.<p> 
  3.  * 仿音悅臺(tái)播放頁面的具體實(shí)現(xiàn),組合控件的形式 
  4.  */ 
  5. public class YytPlayer extends YytLayout { 
  6.     private IjkController mIjkController; 
  7.     private IjkVideoView mIjkVideoView; 
  8.     private ImageView mIvAvatar; 
  9.     private TextView mTvName; 
  10.     private TextView mTvTime; 
  11.     private TextView mTvTitle; 
  12.     private TextView mTvDesc; 
  13.     private RecyclerView mYytRecyclerView; 
  14.     private VideoListAdapter mVideoListAdapter; 
  15.     public YytPlayer(Context context, AttributeSet attrs) { 
  16.         super(context, attrs); 
  17.         init(context, attrs); 
  18.     } 
  19.     private void init(Context context, AttributeSet attrs) { 
  20.         // 繼承YytLayout并且通過merge標(biāo)簽減少層級來實(shí)現(xiàn)組合控件 
  21.         LayoutInflater.from(context).inflate(R.layout.yyt_player, this, true); 
  22.         setOnLayoutStateListener(new OnLayoutStateListener() { 
  23.             @Override 
  24.             public void onClose() { 
  25.                 setVisibility(View.INVISIBLE); 
  26.                 mIjkVideoView.release(true); 
  27.             } 
  28.         }); 
  29.         mIjkVideoView = (IjkVideoView) findViewById(R.id.ijk_player_view); 
  30.         final int scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); 
  31.         mIjkVideoView.setOnTouchListener(new OnTouchListener() { 
  32.             float mDownX = 0; 
  33.             float mDownY = 0; 
  34.             boolean mClickCancel; 
  35.             @Override 
  36.             public boolean onTouch(View v, MotionEvent event) { 
  37.                 float x = event.getX(); 
  38.                 float y = event.getY(); 
  39.                 switch (event.getAction()) { 
  40.                     case MotionEvent.ACTION_DOWN: 
  41.                         mDownX = x; 
  42.                         mDownY = y; 
  43.                         break; 
  44.                     case MotionEvent.ACTION_MOVE: 
  45.                         if (Math.abs(mDownX - x) > scaledTouchSlop || Math.abs(mDownY - y) > scaledTouchSlop) { 
  46.                             mClickCancel = true
  47.                         } 
  48.                         break; 
  49.                     case MotionEvent.ACTION_UP: 
  50.                         if (!mClickCancel && Math.abs(mDownX - x) <= scaledTouchSlop && Math.abs(mDownY - y) <= scaledTouchSlop) { 
  51.                             // 點(diǎn)擊事件偶爾失效,只好這里自己解決了 
  52.                             if (isHorizontalDragEnable()) { 
  53.                                 expand(); 
  54.                             } else { 
  55.                                 mIjkVideoView.toggleMediaControlsVisibility(); 
  56.                             } 
  57.                         } 
  58.                         mClickCancel = false
  59.                         break; 
  60.                     case MotionEvent.ACTION_CANCEL: 
  61.                         mClickCancel = false
  62.                         break; 
  63.                 } 
  64.                 return true
  65.             } 
  66.         }); 
  67.         mIvAvatar = (ImageView) findViewById(R.id.iv_avatar); 
  68.         mTvName = (TextView) findViewById(R.id.tv_name); 
  69.         mTvTime = (TextView) findViewById(R.id.tv_time); 
  70.         mTvTitle = (TextView) findViewById(R.id.tv_title); 
  71.         mTvDesc = (TextView) findViewById(R.id.tv_desc); 
  72.         mVideoListAdapter = new VideoListAdapter(); 
  73.         mVideoListAdapter.setOnItemClickCallback(new OnItemClickCallback() { 
  74.             @Override 
  75.             public void onClick(View viewint position) { 
  76.                 int pos = (Integerview.getTag(); 
  77.                 VideoSummary summary = mVideoListAdapter.getData().get(pos); 
  78.                 playVideo(mVideoListAdapter.getData(), summary); 
  79.             } 
  80.         }); 
  81.         mYytRecyclerView = (RecyclerView) findViewById(R.id.yyt_recycler_view); 
  82.         GridLayoutManager gridLayoutManager = new GridLayoutManager(context, 2, LinearLayoutManager.VERTICAL, false); 
  83.         mYytRecyclerView.setLayoutManager(gridLayoutManager); 
  84.         mYytRecyclerView.setNestedScrollingEnabled(false); 
  85.         mYytRecyclerView.addItemDecoration(new VideoListItemDecoration(context)); 
  86.         mYytRecyclerView.setAdapter(mVideoListAdapter); 
  87.     } 
  88.     // 播放視頻 
  89.     private void playVideo(String path, String name) { 
  90.         try { 
  91.             if (mIjkController == null) { 
  92.                 IjkMediaPlayer.loadLibrariesOnce(null); 
  93.                 IjkMediaPlayer.native_profileBegin("libijkplayer.so"); 
  94.                 mIjkController = new IjkController(mIjkVideoView, name); 
  95.                 mIjkController.setOnViewStateListener(new IjkController.OnViewStateListener() { 
  96.                     @Override 
  97.                     public void onBackPress() { 
  98.                         stop(); 
  99.                     } 
  100.                 }); 
  101.                 mIjkVideoView.setMediaController(mIjkController); 
  102.                 mIjkVideoView.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() { 
  103.                     @Override 
  104.                     public void onPrepared(IMediaPlayer mp) { 
  105.                         mIjkVideoView.start(); 
  106.                     } 
  107.                 }); 
  108.                 mIjkVideoView.setOnErrorListener(new IMediaPlayer.OnErrorListener() { 
  109.                     @Override 
  110.                     public boolean onError(IMediaPlayer mp, int what, int extra) { 
  111.                         Toast.makeText(getContext(), "視頻播放出錯(cuò)了╮(╯Д╰)╭", Toast.LENGTH_SHORT).show(); 
  112.                         return true
  113.                     } 
  114.                 }); 
  115.             } else { 
  116.                 // 重新設(shè)置視頻名字 
  117.                 mIjkController.setVideoName(name); 
  118.             } 
  119.             // 設(shè)置這個(gè)TextureView播放器縮放就正常了 
  120.             mIjkVideoView.setRender(IjkVideoView.RENDER_TEXTURE_VIEW); 
  121.             // 因?yàn)槊看蝧etRender都會(huì)移除view再添加,為了縮放效果這里控制器是添加到IjkVideoView中的,所以這里也要重新添加才能在IjkVideoView的最上面 
  122.             mIjkController.updateControlView(); 
  123.             // 顯示加載條 
  124.             mIjkController.showProgress(); 
  125.             // 播放視頻 
  126.             mIjkVideoView.setVideoURI(Uri.parse(path)); 
  127.         } catch (UnsatisfiedLinkError e) { 
  128.             e.printStackTrace(); 
  129.             Toast.makeText(getContext(), "你的CPU是" + Build.CPU_ABI + ",當(dāng)前播放器使用的編譯版本" + BuildConfig.FLAVOR + "不匹配!", Toast.LENGTH_LONG).show(); 
  130.         } 
  131.     } 
  132.     /** 
  133.      * 顯示布局,并且播放視頻 
  134.      * 
  135.      * @param data    視頻列表,用于播放頁面下面的列表布局 
  136.      * @param summary 播放的視頻信息 
  137.      */ 
  138.     public void playVideo(List<VideoSummary> data, VideoSummary summary) { 
  139.         // 拿到數(shù)據(jù),設(shè)置到播放的布局的相關(guān)信息 
  140.         Glide.with(getContext()).load(summary.mTopicImg).transform(new GlideCircleTransform(getContext())).into(mIvAvatar); 
  141.         mTvName.setText(summary.mTopicName); 
  142.         mTvTime.setText(summary.mPtime); 
  143.         mTvTitle.setText(Html.fromHtml(summary.mTitle)); 
  144.         if (summary.mDescription.isEmpty()) { 
  145.             mTvDesc.setText(summary.mTopicDesc); 
  146.         } else { 
  147.             mTvDesc.setText(Html.fromHtml(summary.mDescription)); 
  148.         } 
  149.         // 設(shè)置YytLayout可見,并且展開 
  150.         setVisibility(View.VISIBLE); 
  151.         expand(); 
  152.         mVideoListAdapter.setData(data); 
  153.         mVideoListAdapter.setItemWidth(mYytRecyclerView.getWidth() / 2); 
  154.         mVideoListAdapter.notifyDataSetChanged(); 
  155.         // 播放視頻 
  156.         playVideo(summary.mMp4HdUrl == null ? summary.mMp4Url : summary.mMp4HdUrl, summary.mTitle); 
  157.     } 
  158.     // 開始播放 
  159.     public void start() { 
  160.         if (mIjkVideoView != null && !mIjkVideoView.isPlaying()) { 
  161.             mIjkVideoView.start(); 
  162.         } 
  163.     } 
  164.     // 暫停播放 
  165.     public void pause() { 
  166.         if (mIjkVideoView != null && mIjkVideoView.isPlaying()) { 
  167.             mIjkVideoView.pause(); 
  168.         } 
  169.     } 
  170.     // 停止播放 
  171.     public void stop() { 
  172.         setVisibility(View.INVISIBLE); 
  173.         if (mIjkVideoView != null) { 
  174.             mIjkVideoView.release(true); 
  175.         } 
  176.     } 
  177.     public boolean isShowing() { 
  178.         return getVisibility() == VISIBLE; 
  179.     } 

 

4.總結(jié)

說難也不難,就是各種摳細(xì)節(jié)需要腦洞,各位不妨看到好玩的交互自己打開腦洞一下,接下來可能要實(shí)現(xiàn)下 UC 瀏覽器播放器的效果,感覺也是非常有意思。

責(zé)任編輯:龐桂玉 來源: 安卓巴士Android開發(fā)者門戶
相關(guān)推薦

2022-04-12 07:37:08

CSS滾動(dòng)視差效果前端

2012-02-22 15:51:01

Android視覺效果UI

2013-07-23 16:33:27

Android視覺效果UI

2013-07-23 10:30:48

Android Des應(yīng)用創(chuàng)新

2010-01-18 15:39:41

互聯(lián)網(wǎng)

2015-12-03 09:53:15

jQuery焦點(diǎn)圖動(dòng)畫

2015-12-07 09:05:37

HTML5動(dòng)畫源碼

2013-01-08 11:00:06

YouTubeAJAXCSS

2021-12-28 10:18:16

微軟Windows 11Mica

2024-07-12 09:01:37

404頁面代碼

2016-01-18 10:14:44

jQuery相冊動(dòng)畫

2022-07-21 07:05:13

粒子動(dòng)畫CSS

2011-09-02 13:57:11

jQuery

2023-10-08 20:32:59

CSS定義Loading

2010-04-28 11:14:20

Windows 7桌面

2010-06-23 09:41:35

惠普阿凡達(dá)刀片

2011-08-19 09:15:01

HTML 5

2015-01-14 15:27:20

Androidsplash

2024-07-04 11:25:34

2017-07-18 16:00:09

炫酷動(dòng)畫開源框架APP
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號