- 浏览: 1065632 次
- 性别:
- 来自: 南昌
文章分类
- 全部博客 (276)
- 生活 (1)
- 代码之美 (22)
- Media (7)
- Android Widget (3)
- Android Intent (1)
- Android Activity (4)
- UI event handle--UI事件处理机制 (2)
- Java基础知识 (12)
- android Databases (5)
- Android 系统知识 (70)
- 平常遇到的问题与解决方法 (38)
- Android TextView/EditView (2)
- Thinking Java (1)
- android webkit (6)
- JSON (1)
- XML (4)
- HTTP (1)
- Google Weather API (1)
- android 2.3 NFC (10)
- android app (20)
- android framework (7)
- C++ (2)
- android System (5)
- Pthread (1)
- Wifi (8)
- Unix/Linux C (8)
- Android 4.0 (1)
- Mail (1)
- Smack 源码学习 (4)
- iOS (4)
- Android (1)
- git (1)
- Gallery3d (2)
- React-Natice (1)
最新评论
-
dd18349182956:
你是用的smack哪个版本?我用的smack4.1.3和sma ...
关于socket长连接的心跳包 -
xukaiyin:
全英文
getApplicationContext()与this,getBaseContext() -
裂风矢:
...
<category android:name="android.intent.category.DEFAULT" /> 惹的祸 -
xanthodont:
mark一下
XMPP——Smack -
Evilover3:
mark一下,学习了
XMPP——Smack
android 的mediaPlayer 有自带的MediaControl.我们不比自己重写这个控件:
A view containing controls for a MediaPlayer. Typically contains the buttons like "Play/Pause", "Rewind", "Fast Forward" and a progress slider. It takes care of synchronizing the controls with the state of the MediaPlayer.
The way to use this class is to instantiate it programatically. The MediaController will create a default set of controls and put them in a window floating above your application. Specifically, the controls will float above the view specified with setAnchorView(). The window will disappear if left idle for three seconds and reappear when the user touches the anchor view.
Functions like show() and hide() have no effect when MediaController is created in an xml layout. MediaController will hide and show the buttons according to these rules:
The "previous" and "next" buttons are hidden until setPrevNextListeners() has been called
The "previous" and "next" buttons are visible but disabled if setPrevNextListeners() was called with null listeners
The "rewind" and "fastforward" buttons are shown unless requested otherwise by using the MediaController(Context, boolean) constructor with the boolean set to false
package android.widget;
import android.content.Context;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.SeekBar.OnSeekBarChangeListener;
import com.android.internal.policy.PolicyManager;
import java.util.Formatter;
import java.util.Locale;
/**
* A view containing controls for a MediaPlayer. Typically contains the buttons
* like "Play/Pause", "Rewind", "Fast Forward" and a progress slider. It takes
* care of synchronizing the controls with the state of the MediaPlayer.
* <p>
* The way to use this class is to instantiate it programatically. The
* MediaController will create a default set of controls and put them in a
* window floating above your application. Specifically, the controls will float
* above the view specified with setAnchorView(). The window will disappear if
* left idle for three seconds and reappear when the user touches the anchor
* view.
* <p>
* Functions like show() and hide() have no effect when MediaController is
* created in an xml layout.
*
* MediaController will hide and show the buttons according to these rules:
* <ul>
* <li>The "previous" and "next" buttons are hidden until setPrevNextListeners()
* has been called
* <li>The "previous" and "next" buttons are visible but disabled if
* setPrevNextListeners() was called with null listeners
* <li>The "rewind" and "fastforward" buttons are shown unless requested
* otherwise by using the MediaController(Context, boolean) constructor with the
* boolean set to false
* </ul>
*/
public class MediaController extends FrameLayout {
private MediaPlayerControl mPlayer;
private Context mContext;
private View mAnchor;
private View mRoot;
private WindowManager mWindowManager;
private Window mWindow;
private View mDecor;
private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime;
private boolean mShowing;
private boolean mDragging;
private static final int sDefaultTimeout = 3000;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private boolean mUseFastForward;
private boolean mFromXml;
private boolean mListenersSet;
private View.OnClickListener mNextListener, mPrevListener;
StringBuilder mFormatBuilder;
Formatter mFormatter;
private ImageButton mPauseButton;
private ImageButton mFfwdButton;
private ImageButton mRewButton;
private ImageButton mNextButton;
private ImageButton mPrevButton;
public MediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = this;
mContext = context;
mUseFastForward = true;
mFromXml = true;
}
@Override
public void onFinishInflate() {
if (mRoot != null)
initControllerView(mRoot);
}
/×在这里设置是否使用FastForward而不是Next;useFastForward=false时使用 Next/Prevouse按钮所以我们在实例化MediaControl是调用这个构造函数,并且 useFastForward=false×/
public MediaController(Context context, boolean useFastForward) {
super(context);
mContext = context;
mUseFastForward = useFastForward;
initFloatingWindow();
}
public MediaController(Context context) {
super(context);
mContext = context;
mUseFastForward = true;
initFloatingWindow();
}
private void initFloatingWindow() {
mWindowManager = (WindowManager) mContext.getSystemService("window");
mWindow = PolicyManager.makeNewWindow(mContext);
mWindow.setWindowManager(mWindowManager, null, null);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mDecor = mWindow.getDecorView();
mDecor.setOnTouchListener(mTouchListener);
mWindow.setContentView(this);
mWindow.setBackgroundDrawableResource(android.R.color.transparent);
// While the media controller is up, the volume control keys should
// affect the media stream type
mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
requestFocus();
}
private OnTouchListener mTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mShowing) {
hide();
}
}
return false;
}
};
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
/**
* Set the view that acts as the anchor for the control view. This can for
* example be a VideoView, or your Activity's main view.
*
* @param view
* The view to which to anchor the controller when it is visible.
*/
public void setAnchorView(View view) {
mAnchor = view;
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT);
removeAllViews();
View v = makeControllerView();
addView(v, frameParams);
}
/**
* Create the view that holds the widgets that control playback. Derived
* classes can override this to create their own.
*
* @return The controller view.
* @hide This doesn't work as advertised
*/
protected View makeControllerView() {
LayoutInflater inflate = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRoot = inflate.inflate(com.android.internal.R.layout.media_controller,
null);
initControllerView(mRoot);
return mRoot;
}
private void initControllerView(View v) {
mPauseButton = (ImageButton) v
.findViewById(com.android.internal.R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mFfwdButton = (ImageButton) v
.findViewById(com.android.internal.R.id.ffwd);
if (mFfwdButton != null) {
mFfwdButton.setOnClickListener(mFfwdListener);
if (!mFromXml) {
mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE
: View.GONE);
}
}
mRewButton = (ImageButton) v
.findViewById(com.android.internal.R.id.rew);
if (mRewButton != null) {
mRewButton.setOnClickListener(mRewListener);
if (!mFromXml) {
mRewButton.setVisibility(mUseFastForward ? View.VISIBLE
: View.GONE);
}
}
// By default these are hidden. They will be enabled when
// setPrevNextListeners() is called
mNextButton = (ImageButton) v
.findViewById(com.android.internal.R.id.next);
if (mNextButton != null && !mFromXml && !mListenersSet) {
mNextButton.setVisibility(View.GONE);
}
mPrevButton = (ImageButton) v
.findViewById(com.android.internal.R.id.prev);
if (mPrevButton != null && !mFromXml && !mListenersSet) {
mPrevButton.setVisibility(View.GONE);
}
mProgress = (ProgressBar) v
.findViewById(com.android.internal.R.id.mediacontroller_progress);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
}
mEndTime = (TextView) v.findViewById(com.android.internal.R.id.time);
mCurrentTime = (TextView) v
.findViewById(com.android.internal.R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
installPrevNextListeners();
}
/**
* Show the controller on screen. It will go away automatically after 3
* seconds of inactivity.
*/
public void show() {
show(sDefaultTimeout);
}
/**
* Show the controller on screen. It will go away automatically after
* 'timeout' milliseconds of inactivity.
*
* @param timeout
* The timeout in milliseconds. Use 0 to show the controller
* until hide() is called.
*/
//我们可以在这里设置MediaControl显示的位置:由P.x与P.y决定
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
int[] anchorpos = new int[2];
mAnchor.getLocationOnScreen(anchorpos);
WindowManager.LayoutParams p = new WindowManager.LayoutParams();
p.gravity = Gravity.TOP;
p.width = mAnchor.getWidth();
p.height = LayoutParams.WRAP_CONTENT;
p.x = 0;
p.y = anchorpos[1] + mAnchor.getHeight() - p.height;
p.format = PixelFormat.TRANSLUCENT;
p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
p.token = null;
p.windowAnimations = 0; // android.R.style.DropDownAnimationDown;
mWindowManager.addView(mDecor, p);
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.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
Message msg = mHandler.obtainMessage(FADE_OUT);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(msg, timeout);
}
}
public boolean isShowing() {
return mShowing;
}
/**
* Remove the controller from the screen.
*/
public void hide() {
if (mAnchor == null)
return;
if (mShowing) {
try {
mHandler.removeMessages(SHOW_PROGRESS);
mWindowManager.removeView(mDecor);
} catch (IllegalArgumentException ex) {
Log.w("MediaController", "already removed");
}
mShowing = false;
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
int pos;
switch (msg.what) {
case FADE_OUT:
hide();
break;
case SHOW_PROGRESS:
pos = setProgress();
if (!mDragging && mShowing && mPlayer.isPlaying()) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
}
break;
}
}
};
private String stringForTime(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();
}
}
private int setProgress() {
if (mPlayer == null || mDragging) {
return 0;
}
int position = mPlayer.getCurrentPosition();
int duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
// use long to avoid overflow
long pos = 1000L * position / duration;
mProgress.setProgress((int) pos);
}
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
}
if (mEndTime != null)
mEndTime.setText(stringForTime(duration));
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime(position));
return position;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
show(sDefaultTimeout);
return true;
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
return false;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0
&& event.isDown()
&& (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
|| keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
|| keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
// don't show the controls for volume adjustment
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK
|| keyCode == KeyEvent.KEYCODE_MENU) {
hide();
return true;
} else {
show(sDefaultTimeout);
}
return super.dispatchKeyEvent(event);
}
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
}
};
private void updatePausePlay() {
if (mRoot == null)
return;
ImageButton button = (ImageButton) mRoot
.findViewById(com.android.internal.R.id.pause);
if (button == null)
return;
if (mPlayer.isPlaying()) {
button
.setImageResource(com.android.internal.R.drawable.ic_media_pause);
} else {
button
.setImageResource(com.android.internal.R.drawable.ic_media_play);
}
}
private void doPauseResume() {
if (mPlayer.isPlaying()) {
mPlayer.pause();
} else {
mPlayer.start();
}
updatePausePlay();
}
// There are two scenarios that can trigger the seekbar listener to trigger:
//
// The first is the user using the touchpad to adjust the posititon of the
// seekbar's thumb. In this case onStartTrackingTouch is called followed by
// a number of onProgressChanged notifications, concluded by
// onStopTrackingTouch.
// We're setting the field "mDragging" to true for the duration of the
// dragging
// session to avoid jumps in the position in case of ongoing playback.
//
// The second scenario involves the user operating the scroll ball, in this
// case there WON'T BE onStartTrackingTouch/onStopTrackingTouch
// notifications,
// we will simply apply the updated position without suspending regular
// updates.
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
show(3600000);
mDragging = true;
// By removing these pending progress messages we make sure
// that a) we won't update the progress while the user adjusts
// the seekbar and b) once the user is done dragging the thumb
// we will post one of these messages to the queue again and
// this ensures that there will be exactly one message queued up.
mHandler.removeMessages(SHOW_PROGRESS);
}
public void onProgressChanged(SeekBar bar, int progress,
boolean fromuser) {
if (!fromuser) {
// We're not interested in programmatically generated changes to
// the progress bar's position.
return;
}
long duration = mPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mPlayer.seekTo((int) newposition);
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime((int) newposition));
}
public void onStopTrackingTouch(SeekBar bar) {
mDragging = false;
setProgress();
updatePausePlay();
show(sDefaultTimeout);
// Ensure that progress is properly updated in the future,
// the call to show() does not guarantee this because it is a
// no-op if we are already showing.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
}
};
@Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
}
if (mFfwdButton != null) {
mFfwdButton.setEnabled(enabled);
}
if (mRewButton != null) {
mRewButton.setEnabled(enabled);
}
if (mNextButton != null) {
mNextButton.setEnabled(enabled && mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setEnabled(enabled && mPrevListener != null);
}
if (mProgress != null) {
mProgress.setEnabled(enabled);
}
super.setEnabled(enabled);
}
private View.OnClickListener mRewListener = new View.OnClickListener() {
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos -= 5000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
}
};
private View.OnClickListener mFfwdListener = new View.OnClickListener() {
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos += 15000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
}
};
private void installPrevNextListeners() {
if (mNextButton != null) {
mNextButton.setOnClickListener(mNextListener);
mNextButton.setEnabled(mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setOnClickListener(mPrevListener);
mPrevButton.setEnabled(mPrevListener != null);
}
}
public void setPrevNextListeners(View.OnClickListener next,
View.OnClickListener prev) {
mNextListener = next;
mPrevListener = prev;
mListenersSet = true;
if (mRoot != null) {
installPrevNextListeners();
if (mNextButton != null && !mFromXml) {
mNextButton.setVisibility(View.VISIBLE);
}
if (mPrevButton != null && !mFromXml) {
mPrevButton.setVisibility(View.VISIBLE);
}
}
}
public interface MediaPlayerControl {
void start();
void pause();
int getDuration();
int getCurrentPosition();
void seekTo(int pos);
boolean isPlaying();
int getBufferPercentage();
};
}
我之前自定义布局是这样做的:先看懂它原来的代码,然后把它相关的代码复制到自己的工程里面变成MyMediaControl,然后修改相关的XML,在相对应的地方模仿原来的方式增加一些监听事件
A view containing controls for a MediaPlayer. Typically contains the buttons like "Play/Pause", "Rewind", "Fast Forward" and a progress slider. It takes care of synchronizing the controls with the state of the MediaPlayer.
The way to use this class is to instantiate it programatically. The MediaController will create a default set of controls and put them in a window floating above your application. Specifically, the controls will float above the view specified with setAnchorView(). The window will disappear if left idle for three seconds and reappear when the user touches the anchor view.
Functions like show() and hide() have no effect when MediaController is created in an xml layout. MediaController will hide and show the buttons according to these rules:
The "previous" and "next" buttons are hidden until setPrevNextListeners() has been called
The "previous" and "next" buttons are visible but disabled if setPrevNextListeners() was called with null listeners
The "rewind" and "fastforward" buttons are shown unless requested otherwise by using the MediaController(Context, boolean) constructor with the boolean set to false
package android.widget;
import android.content.Context;
import android.graphics.PixelFormat;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.SeekBar.OnSeekBarChangeListener;
import com.android.internal.policy.PolicyManager;
import java.util.Formatter;
import java.util.Locale;
/**
* A view containing controls for a MediaPlayer. Typically contains the buttons
* like "Play/Pause", "Rewind", "Fast Forward" and a progress slider. It takes
* care of synchronizing the controls with the state of the MediaPlayer.
* <p>
* The way to use this class is to instantiate it programatically. The
* MediaController will create a default set of controls and put them in a
* window floating above your application. Specifically, the controls will float
* above the view specified with setAnchorView(). The window will disappear if
* left idle for three seconds and reappear when the user touches the anchor
* view.
* <p>
* Functions like show() and hide() have no effect when MediaController is
* created in an xml layout.
*
* MediaController will hide and show the buttons according to these rules:
* <ul>
* <li>The "previous" and "next" buttons are hidden until setPrevNextListeners()
* has been called
* <li>The "previous" and "next" buttons are visible but disabled if
* setPrevNextListeners() was called with null listeners
* <li>The "rewind" and "fastforward" buttons are shown unless requested
* otherwise by using the MediaController(Context, boolean) constructor with the
* boolean set to false
* </ul>
*/
public class MediaController extends FrameLayout {
private MediaPlayerControl mPlayer;
private Context mContext;
private View mAnchor;
private View mRoot;
private WindowManager mWindowManager;
private Window mWindow;
private View mDecor;
private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime;
private boolean mShowing;
private boolean mDragging;
private static final int sDefaultTimeout = 3000;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private boolean mUseFastForward;
private boolean mFromXml;
private boolean mListenersSet;
private View.OnClickListener mNextListener, mPrevListener;
StringBuilder mFormatBuilder;
Formatter mFormatter;
private ImageButton mPauseButton;
private ImageButton mFfwdButton;
private ImageButton mRewButton;
private ImageButton mNextButton;
private ImageButton mPrevButton;
public MediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = this;
mContext = context;
mUseFastForward = true;
mFromXml = true;
}
@Override
public void onFinishInflate() {
if (mRoot != null)
initControllerView(mRoot);
}
/×在这里设置是否使用FastForward而不是Next;useFastForward=false时使用 Next/Prevouse按钮所以我们在实例化MediaControl是调用这个构造函数,并且 useFastForward=false×/
public MediaController(Context context, boolean useFastForward) {
super(context);
mContext = context;
mUseFastForward = useFastForward;
initFloatingWindow();
}
public MediaController(Context context) {
super(context);
mContext = context;
mUseFastForward = true;
initFloatingWindow();
}
private void initFloatingWindow() {
mWindowManager = (WindowManager) mContext.getSystemService("window");
mWindow = PolicyManager.makeNewWindow(mContext);
mWindow.setWindowManager(mWindowManager, null, null);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mDecor = mWindow.getDecorView();
mDecor.setOnTouchListener(mTouchListener);
mWindow.setContentView(this);
mWindow.setBackgroundDrawableResource(android.R.color.transparent);
// While the media controller is up, the volume control keys should
// affect the media stream type
mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
requestFocus();
}
private OnTouchListener mTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mShowing) {
hide();
}
}
return false;
}
};
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
/**
* Set the view that acts as the anchor for the control view. This can for
* example be a VideoView, or your Activity's main view.
*
* @param view
* The view to which to anchor the controller when it is visible.
*/
public void setAnchorView(View view) {
mAnchor = view;
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT);
removeAllViews();
View v = makeControllerView();
addView(v, frameParams);
}
/**
* Create the view that holds the widgets that control playback. Derived
* classes can override this to create their own.
*
* @return The controller view.
* @hide This doesn't work as advertised
*/
protected View makeControllerView() {
LayoutInflater inflate = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRoot = inflate.inflate(com.android.internal.R.layout.media_controller,
null);
initControllerView(mRoot);
return mRoot;
}
private void initControllerView(View v) {
mPauseButton = (ImageButton) v
.findViewById(com.android.internal.R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mFfwdButton = (ImageButton) v
.findViewById(com.android.internal.R.id.ffwd);
if (mFfwdButton != null) {
mFfwdButton.setOnClickListener(mFfwdListener);
if (!mFromXml) {
mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE
: View.GONE);
}
}
mRewButton = (ImageButton) v
.findViewById(com.android.internal.R.id.rew);
if (mRewButton != null) {
mRewButton.setOnClickListener(mRewListener);
if (!mFromXml) {
mRewButton.setVisibility(mUseFastForward ? View.VISIBLE
: View.GONE);
}
}
// By default these are hidden. They will be enabled when
// setPrevNextListeners() is called
mNextButton = (ImageButton) v
.findViewById(com.android.internal.R.id.next);
if (mNextButton != null && !mFromXml && !mListenersSet) {
mNextButton.setVisibility(View.GONE);
}
mPrevButton = (ImageButton) v
.findViewById(com.android.internal.R.id.prev);
if (mPrevButton != null && !mFromXml && !mListenersSet) {
mPrevButton.setVisibility(View.GONE);
}
mProgress = (ProgressBar) v
.findViewById(com.android.internal.R.id.mediacontroller_progress);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
}
mEndTime = (TextView) v.findViewById(com.android.internal.R.id.time);
mCurrentTime = (TextView) v
.findViewById(com.android.internal.R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
installPrevNextListeners();
}
/**
* Show the controller on screen. It will go away automatically after 3
* seconds of inactivity.
*/
public void show() {
show(sDefaultTimeout);
}
/**
* Show the controller on screen. It will go away automatically after
* 'timeout' milliseconds of inactivity.
*
* @param timeout
* The timeout in milliseconds. Use 0 to show the controller
* until hide() is called.
*/
//我们可以在这里设置MediaControl显示的位置:由P.x与P.y决定
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
int[] anchorpos = new int[2];
mAnchor.getLocationOnScreen(anchorpos);
WindowManager.LayoutParams p = new WindowManager.LayoutParams();
p.gravity = Gravity.TOP;
p.width = mAnchor.getWidth();
p.height = LayoutParams.WRAP_CONTENT;
p.x = 0;
p.y = anchorpos[1] + mAnchor.getHeight() - p.height;
p.format = PixelFormat.TRANSLUCENT;
p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
p.token = null;
p.windowAnimations = 0; // android.R.style.DropDownAnimationDown;
mWindowManager.addView(mDecor, p);
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.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
Message msg = mHandler.obtainMessage(FADE_OUT);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(msg, timeout);
}
}
public boolean isShowing() {
return mShowing;
}
/**
* Remove the controller from the screen.
*/
public void hide() {
if (mAnchor == null)
return;
if (mShowing) {
try {
mHandler.removeMessages(SHOW_PROGRESS);
mWindowManager.removeView(mDecor);
} catch (IllegalArgumentException ex) {
Log.w("MediaController", "already removed");
}
mShowing = false;
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
int pos;
switch (msg.what) {
case FADE_OUT:
hide();
break;
case SHOW_PROGRESS:
pos = setProgress();
if (!mDragging && mShowing && mPlayer.isPlaying()) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
}
break;
}
}
};
private String stringForTime(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();
}
}
private int setProgress() {
if (mPlayer == null || mDragging) {
return 0;
}
int position = mPlayer.getCurrentPosition();
int duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
// use long to avoid overflow
long pos = 1000L * position / duration;
mProgress.setProgress((int) pos);
}
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
}
if (mEndTime != null)
mEndTime.setText(stringForTime(duration));
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime(position));
return position;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
show(sDefaultTimeout);
return true;
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
return false;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0
&& event.isDown()
&& (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
|| keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
|| keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
// don't show the controls for volume adjustment
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK
|| keyCode == KeyEvent.KEYCODE_MENU) {
hide();
return true;
} else {
show(sDefaultTimeout);
}
return super.dispatchKeyEvent(event);
}
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
}
};
private void updatePausePlay() {
if (mRoot == null)
return;
ImageButton button = (ImageButton) mRoot
.findViewById(com.android.internal.R.id.pause);
if (button == null)
return;
if (mPlayer.isPlaying()) {
button
.setImageResource(com.android.internal.R.drawable.ic_media_pause);
} else {
button
.setImageResource(com.android.internal.R.drawable.ic_media_play);
}
}
private void doPauseResume() {
if (mPlayer.isPlaying()) {
mPlayer.pause();
} else {
mPlayer.start();
}
updatePausePlay();
}
// There are two scenarios that can trigger the seekbar listener to trigger:
//
// The first is the user using the touchpad to adjust the posititon of the
// seekbar's thumb. In this case onStartTrackingTouch is called followed by
// a number of onProgressChanged notifications, concluded by
// onStopTrackingTouch.
// We're setting the field "mDragging" to true for the duration of the
// dragging
// session to avoid jumps in the position in case of ongoing playback.
//
// The second scenario involves the user operating the scroll ball, in this
// case there WON'T BE onStartTrackingTouch/onStopTrackingTouch
// notifications,
// we will simply apply the updated position without suspending regular
// updates.
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
show(3600000);
mDragging = true;
// By removing these pending progress messages we make sure
// that a) we won't update the progress while the user adjusts
// the seekbar and b) once the user is done dragging the thumb
// we will post one of these messages to the queue again and
// this ensures that there will be exactly one message queued up.
mHandler.removeMessages(SHOW_PROGRESS);
}
public void onProgressChanged(SeekBar bar, int progress,
boolean fromuser) {
if (!fromuser) {
// We're not interested in programmatically generated changes to
// the progress bar's position.
return;
}
long duration = mPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mPlayer.seekTo((int) newposition);
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime((int) newposition));
}
public void onStopTrackingTouch(SeekBar bar) {
mDragging = false;
setProgress();
updatePausePlay();
show(sDefaultTimeout);
// Ensure that progress is properly updated in the future,
// the call to show() does not guarantee this because it is a
// no-op if we are already showing.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
}
};
@Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
}
if (mFfwdButton != null) {
mFfwdButton.setEnabled(enabled);
}
if (mRewButton != null) {
mRewButton.setEnabled(enabled);
}
if (mNextButton != null) {
mNextButton.setEnabled(enabled && mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setEnabled(enabled && mPrevListener != null);
}
if (mProgress != null) {
mProgress.setEnabled(enabled);
}
super.setEnabled(enabled);
}
private View.OnClickListener mRewListener = new View.OnClickListener() {
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos -= 5000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
}
};
private View.OnClickListener mFfwdListener = new View.OnClickListener() {
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos += 15000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
}
};
private void installPrevNextListeners() {
if (mNextButton != null) {
mNextButton.setOnClickListener(mNextListener);
mNextButton.setEnabled(mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setOnClickListener(mPrevListener);
mPrevButton.setEnabled(mPrevListener != null);
}
}
public void setPrevNextListeners(View.OnClickListener next,
View.OnClickListener prev) {
mNextListener = next;
mPrevListener = prev;
mListenersSet = true;
if (mRoot != null) {
installPrevNextListeners();
if (mNextButton != null && !mFromXml) {
mNextButton.setVisibility(View.VISIBLE);
}
if (mPrevButton != null && !mFromXml) {
mPrevButton.setVisibility(View.VISIBLE);
}
}
}
public interface MediaPlayerControl {
void start();
void pause();
int getDuration();
int getCurrentPosition();
void seekTo(int pos);
boolean isPlaying();
int getBufferPercentage();
};
}
评论
2 楼
追求幸福
2013-12-16
fyc0109 写道
麻烦问下,这个如何自定义布局.
我之前自定义布局是这样做的:先看懂它原来的代码,然后把它相关的代码复制到自己的工程里面变成MyMediaControl,然后修改相关的XML,在相对应的地方模仿原来的方式增加一些监听事件
1 楼
fyc0109
2013-06-24
麻烦问下,这个如何自定义布局.
发表评论
-
Android 画布的旋转
2010-10-11 15:51 4450有时候我们会遇到这样的情况:一些字需要从下到上竖着显示怎么办? ... -
MediaControler 与VideoView和ZoomButtonsController 与WebView
2010-09-26 17:32 1910今天在看WebView.java发现了这个规律:你会发现Zoo ... -
MediaPlayer Error code
2010-07-15 20:22 4121http://www.google.cn/codesearch ... -
Bitmap 压缩问题
2010-05-27 16:48 2284android里只支持JPG格式的编码,而支持了PNG,JPG ... -
MediaScannerReceiver
2010-04-08 17:30 3889源码android/packages/apps/provide ... -
android支持的media文件格式--MediaFile
2010-04-08 17:08 2917很久没有写文章了,今天有空看了有关android media的 ...
相关推荐
在Android开发中,VideoView是用于播放视频的基本组件,而MediaController则是提供用户交互界面,如播放、暂停、音量控制等。当我们需要对默认的MediaController进行自定义,例如改变进度条样式或添加全屏切换功能时...
自定义了MediaController,修改控制器的布局以及进度条,实现全屏半屏的切换功能,可以进入http://blog.csdn.net/daitu_liang/article/details/51312523查看效果
7. **AndroidMediaController.java**:这是一个可能的自定义实现类,通过继承`MediaController`并使用反射技术进行修改。可能包含对原类的扩展,以及对特定方法的覆写或私有成员的访问。 8. **my_control.xml**:这...
在Android开发中,`MediaController`是一个非常重要的组件,它为多媒体播放提供了用户界面,包括播放、暂停、快进、后退等控制按钮。当我们需要自定义或扩展默认的`MediaController`功能时,就需要进行重写。下面将...
该库提供了可轻松自定义的Android 。 基本用户界面 自定义UI 特征 按钮图片可自定义 文字颜色和大小可定制 快进/快退时间可自定义 显示持续时间是可定制的 如果需要,此视图可以保留 支持的播放器 媒体播放器 ...
在Android平台上,开发一款音乐播放器和视频播放器是一项复杂且技术含量高的任务。源码是开发者学习和理解这类应用内部工作原理的重要资源。这里我们深入探讨一下"android音乐播放器和视频播放器源码"所涉及的关键...
Android下使用VideoView配合MediaController播放视频Demo,详细参见博客:http://www.cnblogs.com/plokmju/p/android_VideoView.html
MediaController是Android提供的默认视频控制面板,包括播放/暂停按钮、进度条、全屏按钮等。如果需要自定义,可以创建一个新的类继承自MediaController,并覆盖其构造函数和部分方法。例如,我们可以创建一个...
在Android开发中,VideoView组件是一个非常实用的工具,它允许开发者在应用中集成视频播放功能,类似于ImageView处理图片的方式。然而,在实际使用过程中,可能会遇到“无法播放此视频”的问题,这通常由多种因素...
在Android开发中,视频播放是常见的功能之一,而MediaController是Android系统提供的一个用于控制视频播放的组件。本文将深入探讨如何实现MediaController中的进度条重写以及全屏切换功能。 首先,我们要理解...
对于Android,JW Player利用原生的Android MediaController和ExoPlayer库,确保视频流的流畅播放和良好的性能。在iOS上,它则基于AVFoundation框架,为iPhone和iPad用户带来高质量的视频体验。 JW Player的一个关键...
为了提供更好的用户体验,你还可以考虑添加控制条(如`MediaController`),以便用户可以手动控制播放、暂停和进度。同时,注意处理可能的错误,例如文件不存在或无法播放的情况。 6. **运行与测试**: 在完成...
在 N 版本之后,蓝牙音乐应用根据当前系统的 Android 版本通过构建相应的 ComponentName 来初始化媒体浏览器服务的客户端 MediaBrowser,连接媒体浏览器服务的服务端 MediaBrowserService,获取 MediaController ...
Android自定义视频播放器的代码例子。首先演示了原生控件VideoView和MediaController的联合使用,然后指出该组合的不足之处,最后给出了改进之后的自定义视频播放器的设计思路和功能演示效果。
总结来说,`VideoView`和`MediaController`的组合是Android中播放网络视频的标准方式。通过适当配置和处理,可以实现流畅的播放体验和预加载功能,提升用户满意度。在实际应用中,还需要根据网络状况、设备性能等...
myijkplayer ... private AndroidMediaController mMediaController; private IjkVideoView mVideoView; String mVideoPath = "rtmp://live.hkstv.hk.lxdns.com/live/hks"; @Override protected void
在Android应用开发中,MediaPlayer类是用于播放各种音频和视频资源的核心组件。在这个特定的示例中,我们关注的是如何使用MediaPlayer与进度条(SeekBar)结合,创建一个简单的音频播放器。以下是对这个Android应用...
总结起来,Android中使用`VideoView`播放Rtsp视频涉及的关键步骤包括:设置`VideoView`,提供Rtsp URL,创建并设置`MediaController`,监听准备事件并开始播放。在实际开发中,你还需要关注网络条件、设备兼容性以及...
Android应用程序,用于使用MediaController共享#NowPlaying。特征显示共享的居民通知#NowPlaying 共享文本格式的自定义模式为每种格式模式指定前缀/后缀使用NotificationListenerService获取音乐元数据和插图尝试在...
在Android Studio工程中,VideoView通常配合MediaController来实现视频播放的控制,如播放/暂停、进度调整等功能。 要创建一个视频播放器,我们需要以下步骤: 1. **布局设计**:在XML布局文件中,添加VideoView,...