热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要为大家详细介绍了Android自定义SeekBar实现视频播放进度条的相关资料,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

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

其中进度条如下:

接下来说一说我的思路,上面的进度拖动条有自定义的Thumb,在Thumb正上方有一个PopupWindow窗口,窗口里面显示当前的播放时间。在SeekBar右边有一个文本框显示当前播放时间/总时间。

step1、先来看一看PopupWindow的布局文件,seek_popu.xml,效果如下图所示:

<&#63;xml version="1.0" encoding="utf-8"&#63;> 
 
  
  
 

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、将自定义的拖动条加入到布局文件中,下面是部分代码

 <&#63;xml version="1.0" encoding="utf-8"&#63;> 
 
...... 
 
  
 
   
 
   
  
............... 
 

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);// %1$02d:%2$02d:%3$02d 
 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 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • 本文介绍如何通过SSH协议使用Xshell远程连接到Ubuntu系统。为了实现这一目标,需要确保Ubuntu系统已安装并配置好SSH服务器,并保证网络连通性。 ... [详细]
  • 优化局域网SSH连接延迟问题的解决方案
    本文介绍了解决局域网内SSH连接到服务器时出现长时间等待问题的方法。通过调整配置和优化网络设置,可以显著缩短SSH连接的时间。 ... [详细]
  • 本文介绍如何使用布局文件在Android应用中排列多行TextView和Button,使其占据屏幕的特定比例,并提供示例代码以帮助理解和实现。 ... [详细]
  • 本文介绍了Android开发中Intent的基本概念及其在不同Activity之间的数据传递方式,详细展示了如何通过Intent实现Activity间的跳转和数据传输。 ... [详细]
  • 优化 Android 按钮状态下的背景和文本颜色变化
    本文介绍如何通过 Android 的 Selector 实现按钮在不同状态下(如按压)的背景和文本颜色动态变化。我们将详细讲解实现步骤,并提供完整的代码示例。 ... [详细]
  • 本文详细介绍超文本标记语言(HTML)的基本概念与语法结构。HTML是构建网页的核心语言,通过标记标签描述页面内容,帮助开发者创建结构化、语义化的Web页面。 ... [详细]
  • 本文介绍了多个关于JavaScript的书籍资源、实用工具和编程实例,涵盖从入门到进阶的各个阶段,帮助读者全面提升JavaScript编程能力。 ... [详细]
  • 分享一个简化版的Silverlight链接图项目:Link Map Simplified
    本文介绍了一个使用Silverlight开发的可视化工具,主要用于展示和操作复杂的实体关系图(Graph)。该工具在犯罪调查系统中得到了广泛应用,帮助用户直观地获取和理解相关信息。 ... [详细]
  • 探讨如何从数据库中按分组获取最大N条记录的方法,并分享新年祝福。本文提供多种解决方案,适用于不同数据库系统,如MySQL、Oracle等。 ... [详细]
  • 本文介绍了ArcXML配置文件的分类及其在不同服务中的应用,详细解释了地图配置文件的结构和功能,包括其在Image Service、Feature Service以及ArcMap Server中的使用方法。 ... [详细]
author-avatar
CrazyThree
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有