当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义SeekBar实现视频播放进度条

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

2019年07月24日  | 移动技术网移动技术  | 我要评论
首先来看一下效果图,如下所示: 其中进度条如下: 接下来说一说我的思路,上面的进度拖动条有自定义的thumb,在thumb正上方有一个popupwindow窗口

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

其中进度条如下:

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

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

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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网