我想在我的android中显示视频,该视频应具有全屏显示等功能。视频应位于布局的顶部,文本字段应位于其下方。每当用户单击全屏视图(如youtube中的视图)时,视频都应覆盖整个布局,并具有方向性和纵向性。
我从此链接https://github.com/brucetoo/VideoControllerView获得了帮助,但无法找出在其下方放置文本字段的方法。
这是我的视频控制器类
public class VideoControllerView extends FrameLayout implements VideoGestureListener {
private static final String TAG = "VideoControllerView";
private static final int HANDLER_ANIMATE_OUT = 1;// out animate
private static final int HANDLER_UPDATE_PROGRESS = 2;//cycle update progress
private static final long PROGRESS_SEEK = 500;
private static final long ANIMATE_TIME = 300;
private View mRootView; // root view of this
private SeekBar mSeekBar; //seek bar for video
private TextView mEndTime, mCurrentTime;
private boolean mIsShowing;//controller view showing
private boolean mIsDragging; //is dragging seekBar
private StringBuilder mFormatBuilder;
private Formatter mFormatter;
private GestureDetector mGestureDetector;//gesture detector
private Activity mContext;
private boolean mCanSeekVideo;
private boolean mCanControlVolume;
private boolean mCanControlBrightness;
private String mVideoTitle;
private MediaPlayerControlListener mMediaPlayerControlListener;
private ViewGroup mAnchorView;
private SurfaceView mSurfaceView;
@DrawableRes
private int mExitIcon;
@DrawableRes
private int mPauseIcon;
@DrawableRes
private int mPlayIcon;
@DrawableRes
private int mShrinkIcon;
@DrawableRes
private int mStretchIcon;
//top layout
private View mTopLayout;
private ImageButton mBackButton;
private TextView mTitleText;
//center layout
private View mCenterLayout;
private ImageView mCenterImage;
private ProgressBar mCenterProgress;
private float mCurBrightness = -1;
private int mCurVolume = -1;
private AudioManager mAudioManager;
private int mMaxVolume;
//bottom layout
private View mBottomLayout;
private ImageButton mPauseButton;
private ImageButton mFullscreenButton;
private Handler mHandler = new ControllerViewHandler(this);
public VideoControllerView(Builder builder) {
super(builder.context);
this.mContext = builder.context;
this.mMediaPlayerControlListener = builder.mediaPlayerControlListener;
this.mVideoTitle = builder.videoTitle;
this.mCanSeekVideo = builder.canSeekVideo;
this.mCanControlVolume = builder.canControlVolume;
this.mCanControlBrightness = builder.canControlBrightness;
this.mExitIcon = builder.exitIcon;
this.mPauseIcon = builder.pauseIcon;
this.mPlayIcon = builder.playIcon;
this.mStretchIcon = builder.stretchIcon;
this.mShrinkIcon = builder.shrinkIcon;
this.mSurfaceView = builder.surfaceView;
setAnchorView(builder.anchorView);
this.mSurfaceView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
toggleControllerView();
return false;
}
});
}
public static class Builder {
private Activity context;
private boolean canSeekVideo = true;
private boolean canControlVolume = true;
private boolean canControlBrightness = true;
private String videoTitle = "";
private MediaPlayerControlListener mediaPlayerControlListener;
private ViewGroup anchorView;
private SurfaceView surfaceView;
@DrawableRes
private int exitIcon = R.drawable.video_top_back;
@DrawableRes
private int pauseIcon = R.drawable.ic_media_pause;
@DrawableRes
private int playIcon = R.drawable.ic_media_play;
@DrawableRes
private int shrinkIcon = R.drawable.ic_media_fullscreen_shrink;
@DrawableRes
private int stretchIcon = R.drawable.ic_media_fullscreen_stretch;
//Required
public Builder(@Nullable Activity context,@Nullable MediaPlayerControlListener mediaControlListener){
this.context = context;
this.mediaPlayerControlListener = mediaControlListener;
}
public Builder with(@Nullable Activity context) {
this.context = context;
return this;
}
public Builder withMediaControlListener(@Nullable MediaPlayerControlListener mediaControlListener) {
this.mediaPlayerControlListener = mediaControlListener;
return this;
}
//Options
public Builder withVideoTitle(String videoTitle) {
this.videoTitle = videoTitle;
return this;
}
public Builder withVideoSurfaceView(@Nullable SurfaceView surfaceView){
this.surfaceView = surfaceView;
return this;
}
public Builder exitIcon(@DrawableRes int exitIcon) {
this.exitIcon = exitIcon;
return this;
}
public Builder pauseIcon(@DrawableRes int pauseIcon) {
this.pauseIcon = pauseIcon;
return this;
}
public Builder playIcon(@DrawableRes int playIcon) {
this.playIcon = playIcon;
return this;
}
public Builder shrinkIcon(@DrawableRes int shrinkIcon) {
this.shrinkIcon = shrinkIcon;
return this;
}
public Builder stretchIcon(@DrawableRes int stretchIcon) {
this.stretchIcon = stretchIcon;
return this;
}
public Builder canSeekVideo(boolean canSeekVideo) {
this.canSeekVideo = canSeekVideo;
return this;
}
public Builder canControlVolume(boolean canControlVolume) {
this.canControlVolume = canControlVolume;
return this;
}
public Builder canControlBrightness(boolean canControlBrightness) {
this.canControlBrightness = canControlBrightness;
return this;
}
public VideoControllerView build(@Nullable ViewGroup anchorView) {
this.anchorView = anchorView;
return new VideoControllerView(this);
}
}
/**
* Handler prevent leak memory.
*/
private static class ControllerViewHandler extends Handler {
private final WeakReference<VideoControllerView> mView;
ControllerViewHandler(VideoControllerView view) {
mView = new WeakReference<>(view);
}
@Override
public void handleMessage(Message msg) {
VideoControllerView view = mView.get();
if (view == null || view.mMediaPlayerControlListener == null) {
return;
}
int pos;
switch (msg.what) {
case HANDLER_ANIMATE_OUT:
view.hide();
break;
case HANDLER_UPDATE_PROGRESS://cycle update seek bar progress
pos = view.setSeekProgress();
if (!view.mIsDragging && view.mIsShowing && view.mMediaPlayerControlListener.isPlaying()) {//just in case
//cycle update
msg = obtainMessage(HANDLER_UPDATE_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
}
break;
}
}
}
/**
* Inflate view from exit xml layout
*
* @return the root view of {@link VideoControllerView}
*/
private View makeControllerView() {
LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRootView = inflate.inflate(R.layout.media_controller, null);
initControllerView();
return mRootView;
}
/**
* find all views inside {@link VideoControllerView}
* and init params
*/
private void initControllerView() {
//top layout
mTopLayout = mRootView.findViewById(R.id.layout_top);
mBackButton = mRootView.findViewById(R.id.top_back);
mBackButton.setImageResource(mExitIcon);
if (mBackButton != null) {
mBackButton.requestFocus();
mBackButton.setOnClickListener(mBackListener);
}
mTitleText = mRootView.findViewById(R.id.top_title);
//center layout
mCenterLayout = mRootView.findViewById(R.id.layout_center);
mCenterLayout.setVisibility(GONE);
mCenterImage = mRootView.findViewById(R.id.image_center_bg);
mCenterProgress = mRootView.findViewById(R.id.progress_center);
//bottom layout
mBottomLayout = mRootView.findViewById(R.id.layout_bottom);
mPauseButton = mRootView.findViewById(R.id.bottom_pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
mPauseButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
togglePausePlay();
}
});
}
mFullscreenButton = mRootView.findViewById(R.id.bottom_fullscreen);
if (mFullscreenButton != null) {
mFullscreenButton.requestFocus();
mFullscreenButton.setOnClickListener(mFullscreenListener);
}
mSeekBar = mRootView.findViewById(R.id.bottom_seekbar);
if (mSeekBar != null) {
mSeekBar.setOnSeekBarChangeListener(mSeekListener);
mSeekBar.setMax(1000);
}
mEndTime = mRootView.findViewById(R.id.bottom_time);
mCurrentTime = mRootView.findViewById(R.id.bottom_time_current);
//init formatter
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
}
/**
* show controller view
*/
void show() {
if (!mIsShowing && mAnchorView != null) {
//add controller view to bottom of the AnchorView
FrameLayout.LayoutParams tlp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
mAnchorView.addView(VideoControllerView.this, tlp);
ViewAnimator.putOn(mTopLayout)
.waitForSize(new ViewAnimator.Listeners.Size() {
@Override
public void onSize(ViewAnimator viewAnimator) {
viewAnimator.animate()
.translationY(-mTopLayout.getHeight(), 0)
.duration(ANIMATE_TIME)
.andAnimate(mBottomLayout)
.translationY(mBottomLayout.getHeight(), 0)
.duration(ANIMATE_TIME)
.start(new ViewAnimator.Listeners.Start() {
@Override
public void onStart() {
mIsShowing = true;
mHandler.sendEmptyMessage(HANDLER_UPDATE_PROGRESS);
}
});
}
});
}
setSeekProgress();
if (mPauseButton != null) {
mPauseButton.requestFocus();
}
togglePausePlay();
toggleFullScreen();
//update progress
mHandler.sendEmptyMessage(HANDLER_UPDATE_PROGRESS);
}
/**
* toggle {@link VideoControllerView} show or not
* this can be called when {@link View#onTouchEvent(MotionEvent)} happened
*/
public void toggleControllerView() {
if (!isShowing()) {
show();
} else {
//animate out controller view
Message msg = mHandler.obtainMessage(HANDLER_ANIMATE_OUT);
//remove exist one first
mHandler.removeMessages(HANDLER_ANIMATE_OUT);
mHandler.sendMessageDelayed(msg, 100);
}
}
/**
* if {@link VideoControllerView} is visible
*
* @return showing or not
*/
public boolean isShowing() {
return mIsShowing;
}
/**
* hide controller view with animation
* With custom animation
*/
private void hide() {
if (mAnchorView == null) {
return;
}
ViewAnimator.putOn(mTopLayout)
.animate()
.translationY(-mTopLayout.getHeight())
.duration(ANIMATE_TIME)
.andAnimate(mBottomLayout)
.translationY(mBottomLayout.getHeight())
.duration(ANIMATE_TIME)
.end(new ViewAnimator.Listeners.End() {
@Override
public void onEnd() {
mAnchorView.removeView(VideoControllerView.this);
mHandler.removeMessages(HANDLER_UPDATE_PROGRESS);
mIsShowing = false;
}
});
}
/**
* convert string to time
*
* @param timeMs time to be formatted
* @return 00:00:00
*/
private String stringToTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
mFormatBuilder.setLength(0);
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
/**
* set {@link #mSeekBar} progress
* and video play time {@link #mCurrentTime}
*
* @return current play position
*/
private int setSeekProgress() {
if (mMediaPlayerControlListener == null || mIsDragging) {
return 0;
}
int position = mMediaPlayerControlListener.getCurrentPosition();
int duration = mMediaPlayerControlListener.getDuration();
if (mSeekBar != null) {
if (duration > 0) {
// use long to avoid overflow
long pos = 1000L * position / duration;
mSeekBar.setProgress((int) pos);
}
//get buffer percentage
int percent = mMediaPlayerControlListener.getBufferPercentage();
//set buffer progress
mSeekBar.setSecondaryProgress(percent * 10);
}
if (mEndTime != null)
mEndTime.setText(stringToTime(duration));
if (mCurrentTime != null) {
Log.e(TAG, "position:" + position + " -> duration:" + duration);
mCurrentTime.setText(stringToTime(position));
if(mMediaPlayerControlListener.isComplete()){
mCurrentTime.setText(stringToTime(duration));
}
}
mTitleText.setText(mVideoTitle);
return position;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
mCurVolume = -1;
mCurBrightness = -1;
mCenterLayout.setVisibility(GONE);
// break;// do need bread,should let gestureDetector to handle event
default://gestureDetector handle other MotionEvent
if(mGestureDetector != null)
mGestureDetector.onTouchEvent(event);
}
return true;
}
/**
* toggle pause or play
*/
private void togglePausePlay() {
if (mRootView == null || mPauseButton == null || mMediaPlayerControlListener == null) {
return;
}
if (mMediaPlayerControlListener.isPlaying()) {
mMediaPlayerControlListener.pause();
mPauseButton.setImageResource(mPauseIcon);
} else {
mMediaPlayerControlListener.start();
mPauseButton.setImageResource(mPlayIcon);
}
}
/**
* toggle full screen or not
*/
public void toggleFullScreen() {
if (mRootView == null || mFullscreenButton == null || mMediaPlayerControlListener == null) {
return;
}
if (mMediaPlayerControlListener.isFullScreen()) {
mFullscreenButton.setImageResource(mShrinkIcon);
} else {
mFullscreenButton.setImageResource(mStretchIcon);
}
}
private void doPauseResume() {
if (mMediaPlayerControlListener == null) {
return;
}
if (mMediaPlayerControlListener.isPlaying()) {
mMediaPlayerControlListener.pause();
} else {
mMediaPlayerControlListener.start();
}
togglePausePlay();
}
private void doToggleFullscreen() {
if (mMediaPlayerControlListener == null) {
return;
}
mMediaPlayerControlListener.toggleFullScreen();
}
/**
* Seek bar drag listener
*/
private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
show();
mIsDragging = true;
mHandler.removeMessages(HANDLER_UPDATE_PROGRESS);
}
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
if (mMediaPlayerControlListener == null) {
return;
}
if (!fromuser) {
return;
}
long duration = mMediaPlayerControlListener.getDuration();
long newPosition = (duration * progress) / 1000L;
mMediaPlayerControlListener.seekTo((int) newPosition);
if (mCurrentTime != null)
mCurrentTime.setText(stringToTime((int) newPosition));
}
public void onStopTrackingTouch(SeekBar bar) {
mIsDragging = false;
setSeekProgress();
togglePausePlay();
show();
mHandler.sendEmptyMessage(HANDLER_UPDATE_PROGRESS);
}
};
@Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
}
if (mSeekBar != null) {
mSeekBar.setEnabled(enabled);
}
super.setEnabled(enabled);
}
/**
* set top back click listener
*/
private View.OnClickListener mBackListener = new View.OnClickListener() {
public void onClick(View v) {
mMediaPlayerControlListener.exit();
}
};
/**
* set pause click listener
*/
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void onClick(View v) {
doPauseResume();
show();
}
};
/**
* set full screen click listener
*/
private View.OnClickListener mFullscreenListener = new View.OnClickListener() {
public void onClick(View v) {
doToggleFullscreen();
show();
}
};
/**
* setMediaPlayerControlListener update play state
*
* @param mediaPlayerListener self
*/
public void setMediaPlayerControlListener(MediaPlayerControlListener mediaPlayerListener) {
mMediaPlayerControlListener = mediaPlayerListener;
togglePausePlay();
toggleFullScreen();
}
/**
* set anchor view
*
* @param view view that hold controller view
*/
private void setAnchorView(ViewGroup view) {
mAnchorView = view;
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
//remove all before add view
removeAllViews();
View v = makeControllerView();
addView(v, frameParams);
setGestureListener();
}
/**
* set gesture listen to control media player
* include screen brightness and volume of video
* and seek video play
*/
private void setGestureListener() {
if(mCanControlVolume) {
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
}
mGestureDetector = new GestureDetector(mContext, new ViewGestureListener(mContext, this));
}
@Override
public void onSingleTap() {
toggleControllerView();
}
@Override
public void onHorizontalScroll(boolean seekForward) {
if (mCanSeekVideo) {
if (seekForward) {// seek forward
seekForWard();
} else { //seek backward
seekBackWard();
}
}
}
private void seekBackWard() {
if (mMediaPlayerControlListener == null) {
return;
}
int pos = mMediaPlayerControlListener.getCurrentPosition();
pos -= PROGRESS_SEEK;
mMediaPlayerControlListener.seekTo(pos);
setSeekProgress();
show();
}
private void seekForWard() {
if (mMediaPlayerControlListener == null) {
return;
}
int pos = mMediaPlayerControlListener.getCurrentPosition();
pos += PROGRESS_SEEK;
mMediaPlayerControlListener.seekTo(pos);
setSeekProgress();
show();
}
@Override
public void onVerticalScroll(float percent, int direction) {
if (direction == ViewGestureListener.SWIPE_LEFT) {
if(mCanControlBrightness) {
mCenterImage.setImageResource(R.drawable.video_bright_bg);
updateBrightness(percent);
}
} else {
if(mCanControlVolume) {
mCenterImage.setImageResource(R.drawable.video_volume_bg);
updateVolume(percent);
}
}
}
/**
* update volume by seek percent
*
* @param percent seek percent
*/
private void updateVolume(float percent) {
mCenterLayout.setVisibility(VISIBLE);
if (mCurVolume == -1) {
mCurVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
if (mCurVolume < 0) {
mCurVolume = 0;
}
}
int volume = (int) (percent * mMaxVolume) + mCurVolume;
if (volume > mMaxVolume) {
volume = mMaxVolume;
}
if (volume < 0) {
volume = 0;
}
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
int progress = volume * 100 / mMaxVolume;
mCenterProgress.setProgress(progress);
}
/**
* update brightness by seek percent
*
* @param percent seek percent
*/
private void updateBrightness(float percent) {
if (mCurBrightness == -1) {
mCurBrightness = mContext.getWindow().getAttributes().screenBrightness;
if (mCurBrightness <= 0.01f) {
mCurBrightness = 0.01f;
}
}
mCenterLayout.setVisibility(VISIBLE);
WindowManager.LayoutParams attributes = mContext.getWindow().getAttributes();
attributes.screenBrightness = mCurBrightness + percent;
if (attributes.screenBrightness >= 1.0f) {
attributes.screenBrightness = 1.0f;
} else if (attributes.screenBrightness <= 0.01f) {
attributes.screenBrightness = 0.01f;
}
mContext.getWindow().setAttributes(attributes);
float p = attributes.screenBrightness * 100;
mCenterProgress.setProgress((int) p);
}
/**
* Interface of Media Controller View Which can be callBack
* when {@link android.media.MediaPlayer} or some other media
* players work
*/
public interface MediaPlayerControlListener {
/**
* start play video
*/
void start();
/**
* pause video
*/
void pause();
/**
* get video total time
*
* @return total time
*/
int getDuration();
/**
* get video current position
*
* @return current position
*/
int getCurrentPosition();
/**
* seek video to exactly position
*
* @param position position
*/
void seekTo(int position);
/**
* video is playing state
*
* @return is video playing
*/
boolean isPlaying();
/**
* video is complete
* @return complete or not
*/
boolean isComplete();
/**
* get buffer percent
*
* @return percent
*/
int getBufferPercentage();
/**
* video is full screen
* in order to control image src...
*
* @return fullScreen
*/
boolean isFullScreen();
/**
* toggle fullScreen
*/
void toggleFullScreen();
/**
* exit media player
*/
void exit();
}
}