一緒に書く習慣を身につけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して4日目です。クリックしてイベントの詳細をご覧ください。
VideoViewの紹介
私は以前、ビデオを再生する機能を実現するためにMediaPlayer
+の使用を紹介しました。簡単なビデオ再生機能を実現するための公式パッケージコンポーネントSurfaceView
を偶然見つけました。 +形式はビデオファイルの再生を制御するためにも使用されます。使い方は比較的シンプルで、動画を再生するだけのシナリオに適していますが、その限られた機能は、動画の明るさの調整など、他の機能には適していません。VideoView
MediaPlayer
SurfaceView
MediaPlayer
MediaController
再生コンポーネントに加えて、ビデオ再生、一時停止、早送り、早戻しなどの機能をサポートする、ビデオ再生用の再生操作バー機能を提供するコンポーネントVideoView
もあります。MediaController
さらに、ビデオを再生するために指定された位置にドラッグできるプログレスバー機能も提供します。
使用する
VideoView
このパッケージMediaPlayer
は、同様のMediaPlayer
APIも提供します。たとえばstart
、メソッドはビデオを再生する機能でもありますがsetOnpreparedListener
、メソッドを呼び出してメソッドを実行する前にコールバック結果を設定することをお勧めします。メソッドは、メソッドが呼び出さsetVideoPath
れた後にアクティブに実行されます。prepareAsync
開発者が多くの機能を内部でカプセル化して実装するのにVideoView
役立ちます。実際、内部ソースコードから学習して、より包括的でより完全な自作プレーヤーを実現することもできます。
一般的なAPI | 説明する |
---|---|
setVideoPath | ビデオアセットを設定する |
始める | 遊ぶ |
一時停止 | 一時停止 |
履歴書 | リプレイ |
探す | 指定された場所でプレイ |
isPlaying | ビデオが再生されているかどうか |
getCurrentPosition | 現在の再生位置を取得します |
setMediaController | MediaControllerを設定します |
setOnpreparedListener | ビデオ読み込み完了イベントをリッスンする |
// 实例化videoView
videoView = new VideoView(this);
Uri uri = Uri.fromFile(new File("sdcard/DCIM","新世纪福音战士24.mp4"));
//加载视频资源
videoView.setVideoURI(uri);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.addView(videoView);
setContentView(linearLayout);
//设置监听
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//回调成功并播放视频
videoView.start();
}
});
//创建操作栏
MediaController mediaController = new MediaController(this);
videoView.setMediaController(mediaController);
mediaController.setMediaPlayer(videoView);
复制代码
ソースコード分析
VideoView
2つのコンポーネントがカプセル化MediaController
されたので、以前に実装が試みられた多くの関数が、それらがどのように実装されているかを確認するために使用プロセスで見つかります。
進捗状況の表示
MediaController
表示されると、呼び出し元のメソッドshow
内にpost(mShowProgress);
メソッドが表示されます。
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
if (mPauseButton != null) {
mPauseButton.requestFocus();
}
disableUnsupportedButtons();
updateFloatingWindowLayout();
mWindowManager.addView(mDecor, mDecorLayoutParams);
mShowing = true;
}
updatePausePlay();
// cause the progress bar to be updated even if mShowing
// was already true. This happens, for example, if we're
// paused with the progress bar showing the user hits play.
post(mShowProgress);
if (timeout != 0 && !mAccessibilityManager.isTouchExplorationEnabled()) {
removeCallbacks(mFadeOut);
postDelayed(mFadeOut, timeout);
}
}
复制代码
これmShowProgress
は1つRunnable
であり、内部遅延がそれ自体を呼び出して更新することがわかりsetProgress()
ます。setProgress()
再生の進行状況を読み取り、MediaPlayer
再生情報を更新する方法です。
private final Runnable mShowProgress = new Runnable() {
@Override
public void run() {
int pos = setProgress();
if (!mDragging && mShowing && mPlayer.isPlaying()) {
postDelayed(mShowProgress, 1000 - (pos % 1000));
}
}
};
复制代码
プレイサイズの適応
再生サイズの適応をカスタマイズする前に、VideoView
開発者が内部でビデオ再生の適応を実現するのに直接役立ちます。詳細なコードはonMeasure
直接。コードのおおよそのアルゴリズムはVideoView
、レイアウトの幅と高さ、およびビデオの幅と高さを比較することによって、計算された幅と高さを書き直すことVideoView
です。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//Log.i("@@@@", "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", "
// + MeasureSpec.toString(heightMeasureSpec) + ")");
int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
if (mVideoWidth > 0 && mVideoHeight > 0) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.EXACTLY) {
// the size is fixed
width = widthSpecSize;
height = heightSpecSize;
// for compatibility, we adjust size based on aspect ratio
if ( mVideoWidth * height < width * mVideoHeight ) {
//Log.i("@@@", "image too wide, correcting");
width = height * mVideoWidth / mVideoHeight;
} else if ( mVideoWidth * height > width * mVideoHeight ) {
//Log.i("@@@", "image too tall, correcting");
height = width * mVideoHeight / mVideoWidth;
}
} else if (widthSpecMode == MeasureSpec.EXACTLY) {
// only the width is fixed, adjust the height to match aspect ratio if possible
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
// couldn't match aspect ratio within the constraints
height = heightSpecSize;
}
} else if (heightSpecMode == MeasureSpec.EXACTLY) {
// only the height is fixed, adjust the width to match aspect ratio if possible
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
// couldn't match aspect ratio within the constraints
width = widthSpecSize;
}
} else {
// neither the width nor the height are fixed, try to use actual video size
width = mVideoWidth;
height = mVideoHeight;
if (heightSpecMode == MeasureSpec.AT_MOST && height > heightSpecSize) {
// too tall, decrease both width and height
height = heightSpecSize;
width = height * mVideoWidth / mVideoHeight;
}
if (widthSpecMode == MeasureSpec.AT_MOST && width > widthSpecSize) {
// too wide, decrease both width and height
width = widthSpecSize;
height = width * mVideoHeight / mVideoWidth;
}
}
} else {
// no size yet, just adopt the given spec sizes
}
setMeasuredDimension(width, height);
}
复制代码