Android自定义SeekBar实现视频播放进度条

发布时间 - 2026-01-11 00:27:31    点击率:

本文实例为大家分享了Android实现视频播放进度条的具体代码,供大家参考,具体内容如下

首先来看一下效果图,如下所示:

其中进度条如下:

接下来说一说我的思路,上面的进度拖动条有自定义的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(); 
 } 

当然,这里只是简单的介绍了下自定义进度条,而该进度条的样式都没有展现出来,样式读者可以自己定义。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Android  # SeekBar进度条  # Android视频播放进度条  # Android播放进度条  # Android使用VideoView播放本地视频和网络视频的方法  # Android提高之MediaPlayer播放网络视频的实现方法  # Android使用VideoView出现无法播放此视频问题的解决方法  # 详解Android App中使用VideoView来实现视频播放的方法  # Android播放assets文件里视频文件相关问题分析  # Android如何让WebView中的HTML5页面实现视频全屏播放  # 一个html5播放视频的video控件只支持android的默认格式mp4和3gp  # android webvie指定视频播放器播放网站视频  # android视频播放简单实现示例(VideoView&MediaPlayer)  # Android实现音乐视频播放  # 拖动  # 是一个  # 自定义  # 可选  # 所示  # 进度条  # 中心点  # 播放时间  # 文本框  # 有一个  # 在整个  # 第一个  # 依此类推  # 所需  # 要把  # 再加上  # 第二个  # 已经开始  # 各有  # 能使 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程  深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?  javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  如何基于云服务器快速搭建网站及云盘系统?  如何用虚拟主机快速搭建网站?详细步骤解析  Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转  JS中对数组元素进行增删改移的方法总结  Win11关机界面怎么改_Win11自定义关机画面设置【工具】  大学网站设计制作软件有哪些,如何将网站制作成自己app?  Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】  laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法  如何在Windows服务器上快速搭建网站?  如何在IIS7中新建站点?详细步骤解析  网易LOFTER官网链接 老福特网页版登录地址  如何快速生成凡客建站的专业级图册?  如何在IIS中新建站点并配置端口与物理路径?  香港服务器网站推广:SEO优化与外贸独立站搭建策略  Javascript中的事件循环是如何工作的_如何利用Javascript事件循环优化异步代码?  Laravel全局作用域是什么_Laravel Eloquent Global Scopes应用指南  如何用西部建站助手快速创建专业网站?  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】  Laravel如何实现API速率限制?(Rate Limiting教程)  青岛网站建设如何选择本地服务器?  如何彻底删除建站之星生成的Banner?  大连 网站制作,大连天途有线官网?  ,交易猫的商品怎么发布到网站上去?  Linux后台任务运行方法_nohup与&使用技巧【技巧】  LinuxShell函数封装方法_脚本复用设计思路【教程】  PHP正则匹配日期和时间(时间戳转换)的实例代码  如何在云主机快速搭建网站站点?  java获取注册ip实例  矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?  济南网站建设制作公司,室内设计网站一般都有哪些功能?  深圳网站制作培训,深圳哪些招聘网站比较好?  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?  laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析  详解阿里云nginx服务器多站点的配置  Laravel安装步骤详细教程_Laravel环境搭建指南  Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  如何在搬瓦工VPS快速搭建网站?  英语简历制作免费网站推荐,如何将简历翻译成英文?  详解CentOS6.5 安装 MySQL5.1.71的方法  Android自定义控件实现温度旋转按钮效果  重庆市网站制作公司,重庆招聘网站哪个好?  Android GridView 滑动条设置一直显示状态(推荐)  如何快速生成橙子建站落地页链接?  Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案