这里有新鲜出炉的精品教程,程序狗速度看过来!
Android 是一种基于 Linux 的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由 Google 公司和开放手机联盟领导及开发。尚未有统一中文名称,中国大陆地区较多人使用 "安卓" 或 "安致"。
这篇文章主要为大家详细介绍了 Android 自定义 SeekBar 实现视频播放进度条的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
首先来看一下效果图,如下所示:
其中进度条如下:
接下来说一说我的思路,上面的进度拖动条有自定义的 Thumb,在 Thumb 正上方有一个 PopupWindow 窗口,窗口里面显示当前的播放时间。在 SeekBar 右边有一个文本框显示当前播放时间 / 总时间。
step1、先来看一看 PopupWindow 的布局文件,seek_popu.xml, 效果如下图所示:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/seek_dialog_bg" >
- <!-- 展现当前播放进度时间的文本框-->
- <TextView
- android:id="@+id/dialogSeekTime"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="10dip"
- android:layout_marginTop="12dip"
- android:text="@string/unknow_seek_time"
- android:textColor="@color/black"
- android:textSize="12sp" />
- </RelativeLayout>
step2、自定义一个 SeekBar
- import com.canplay.video.R;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.widget.PopupWindow;
- import android.widget.SeekBar;
- import android.widget.TextView;
- /**
- * 自定义进度拖动条控件
- */
- public class MySeekBar extends SeekBar {
- /**
- * 定义一个展现时间的PopupWindow
- */
- private PopupWindow mPopupWindow;
- private View mView;
- /**
- * 显示时间的TextView
- */
- private TextView dialogSeekTime;
- /**
- * 用来表示该组件在整个屏幕内的绝对坐标,其中 mPosition[0] 代表X坐标,mPosition[1] 代表Y坐标。
- */
- private int[] mPosition;
- /**
- * SeekBar上的Thumb的宽度,即那个托动的小黄点的宽度
- */
- private final int mThumbWidth = 25;
- public MySeekBar(Context context) {
- this(context, null);
- }
- public MySeekBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- mView = LayoutInflater.from(context).inflate(R.layout.seek_popu, null);
- dialogSeekTime = (TextView) mView.findViewById(R.id.dialogSeekTime);
- mPopupWindow = new PopupWindow(mView, mView.getWidth(), mView.getHeight(), true);
- mPosition = new int[2];
- }
- /**
- * 获取控件的宽度
- *
- * @param v
- * @return 控件的宽度
- */
- private int getViewWidth(View v) {
- int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- v.measure(w, h);
- return v.getMeasuredWidth();
- }
- /**
- * 获取控件的高度
- *
- * @param v
- * @return 控件的高度
- */
- private int getViewHeight(View v) {
- int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
- v.measure(w, h);
- return v.getMeasuredHeight();
- }
- /**
- * 隐藏进度拖动条的PopupWindow
- */
- public void hideSeekDialog() {
- if (mPopupWindow != null && mPopupWindow.isShowing()) {
- mPopupWindow.dismiss();
- }
- }
- /**
- * 显示进度拖动条的PopupWindow
- *
- * @param str
- * 时间值
- */
- public void showSeekDialog(String str) {
- dialogSeekTime.setText(str);
- int progress = this.getProgress();
- // 计算每个进度值所占的宽度
- int thumb_x = (int) (progress * (1.0f * (this.getWidth() - 22) / this.getMax())); //22是两边的空白部分宽度
- // 更新后的PopupWindow的Y坐标
- int middle = this.getHeight() / 2 + 120;
- if (mPopupWindow != null) {
- try {
- /*
- * 获取在整个屏幕内的绝对坐标,注意这个值是要从屏幕顶端算起,也就是包括了通知栏的高度。
- * 其中 mPosition[0] 代表X坐标,mPosition[1]代表Y坐标。
- */
- this.getLocationOnScreen(mPosition);
- // 相对某个控件的位置(正左下方),在X、Y方向各有偏移
- mPopupWindow.showAsDropDown(this, (int) mPosition[0], mPosition[1]);
- /*
- * 更新后的PopupWindow的X坐标
- * 首先要把当前坐标值减去PopWindow的宽度的一半,再加上Thumb的宽度一半。
- * 这样才能使PopWindow的中心点和Thumb的中心点的X坐标相等
- */
- int x = thumb_x + mPosition[0] - getViewWidth(mView) / 2 + mThumbWidth / 2;
- // 更新popup窗口的位置
- mPopupWindow.update(x, middle, getViewWidth(mView), getViewHeight(mView));
- } catch (Exception e) {
- }
- }
- }
- }
step3、将自定义的拖动条加入到布局文件中, 下面是部分代码
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@android:color/black" >
- ......
- <!-- 进度拖动条 -->
- <RelativeLayout
- android:id="@+id/seek_bar_container"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/control_btn_container"
- android:background="@drawable/seek_bg" >
- <com.canplay.video.view.MySeekBar
- android:id="@+id/seek_progress"
- android:layout_width="600dip"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true" />
- <TextView
- android:id="@+id/currentTime"
- style="@style/seekTime"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toRightOf="@id/seek_progress"
- android:paddingLeft="20dip"
- android:text="@string/unknow_time" />
- </RelativeLayout>
- ...............
- </RelativeLayout>
step4、在主文件中对拖动条进行托动监听
- mSeekBar = (MySeekBar) findViewById(R.id.seek_progress);
- mSeekBar.setOnSeekBarChangeListener(mSeekBarListener);
- /**
- * 进度拖动条监听器
- */
- private OnSeekBarChangeListener mSeekBarListener = new OnSeekBarChangeListener() {
- // 通知进度已经被修改
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- if (isTouchSeeked) {
- mSeekBar.showSeekDialog(makeTimeString(progress));//动态展示当前播放时间
- } else {
- mSeekBar.hideSeekDialog();
- }
- }
- // 通知用户已经开始一个触摸拖动手势
- public void onStartTrackingTouch(SeekBar seekBar) {
- showControlView(3600000);
- isTouchSeeked = true;
- }
- // 通知用户触摸手势已经结束
- public void onStopTrackingTouch(SeekBar seekBar) {
- Message msg = Message.obtain();
- msg.what = PROGRESS_SEEKTO;
- msg.arg1 = seekBar.getProgress();
- mHandler.removeMessages(PROGRESS_SEEKTO);
- mHandler.sendMessageAtTime(msg, 1000);// 1秒之后开始发送更新进度的消息
- isTouchSeeked = false;
- showControlView(sDefaultTimeout);
- }
- };
其中将进度值转换为时间的方法 makeTimeString(int secs) 如下所示:
- /**
- * 格式化的Builder
- */
- private StringBuilder sFormatBuilder = new StringBuilder();
- /**
- * 格式化的Formatter
- */
- private Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
- /**
- * 格式化的相关属性
- */
- private final Object[] sTimeArgs = new Object[3];
- /**
- * 转换进度值为时间
- *
- * @param secs
- * @return
- */
- private String makeTimeString(int secs) {
- /**
- * %[argument_index$][flags][width]conversion 可选的
- * argument_index 是一个十进制整数,用于表明参数在参数列表中的位置。第一个参数由 "1$"
- * 引用,第二个参数由 "2$" 引用,依此类推。 可选 flags
- * 是修改输出格式的字符集。有效标志集取决于转换类型。 可选 width
- * 是一个非负十进制整数,表明要向输出中写入的最少字符数。 可选 precision
- * 是一个非负十进制整数,通常用来限制字符数。特定行为取决于转换类型。 所需 conversion
- * 是一个表明应该如何格式化参数的字符。给定参数的有效转换集取决于参数的数据类型。
- */
- String durationformat = getString(R.string.durationformat);// <xliff:g
- // id="format">%1$02d:%2$02d:%3$02d</xliff:g>
- sFormatBuilder.setLength(0);
- secs = secs / 1000;
- Object[] timeArgs = sTimeArgs;
- timeArgs[0] = secs / 3600; // 秒
- timeArgs[1] = (secs % 3600) / 60; // 分
- timeArgs[2] = (secs % 3600 % 60) % 60; // 时
- return sFormatter.format(durationformat, timeArgs).toString().trim();
- }
当然,这里只是简单的介绍了下自定义进度条,而该进度条的样式都没有展现出来,样式读者可以自己定义。
来源: http://www.phperz.com/article/17/0606/332683.html