最近要弄个播放器,但是SeekBar没有断断续续的效果都是连续的进度。查了点资料自己重写一个,主要原理是利用Region不断的求并集 实现断断续续的效果:
1.继承SeekBar自定义类中重写onDraw(Canvas canvas)方法 绘制进度条
protected synchronized void onDraw(Canvas canvas) {
if(progressBarWidth!=0&&progressBarWidth!=getWidth()){
changeSizeScale=(float)getWidth()/(float)progressBarWidth;
}
progressBarWidth = getWidth();
progressBarHeight = getHeight();
int pTop=(progressBarHeight-seekBarBgHeight)/2;
int pBottom=(progressBarHeight-seekBarBgHeight)/2+seekBarBgHeight;
Drawable thumb=getThumb();
//绘制进度条背景
Rect bgRect = new Rect(0,pTop,progressBarWidth,pBottom);
canvas.drawRect(bgRect, bgPaint);
//绘制缓冲进度
drawCachProgress(canvas,progressBarWidth,pTop,pBottom);
//绘制播放进度
Rect progressRect = new Rect(0,pTop,thumb.getBounds().left,pBottom);
canvas.drawRect(progressRect, progressPaint);
//绘制控制点
canvas.drawBitmap(controlPointBitmap,thumb.getBounds().left,progressBarHeight/2-controlPointBitmap.getWidth()/2,null);
}
int secondProg=getSecondaryProgress();
float scale=(float)secondProg/(float)getMax();
if((secondProg-lastCachProg)>=0&&(secondProg-lastCachProg)<=2000){//小于2s的都视为没有拖动
if(currentRect==null){
currentRect= new Rect(0,pTop,(int)(scale*progressBarWidth),pBottom);
}
currentRect.right=(int)(scale*progressBarWidth);
}else{//手指拖动了 重新定位
if(currentRect!=null){
currentRect.left=(int)(scale*progressBarWidth);//定位到新的位置
currentRect.right=(int)(scale*progressBarWidth)+1;
}
}
lastCachProg=secondProg;
if(currentRect!=null){
getCachRegion(pTop,pBottom).op(currentRect, Op.UNION);//求并集
}
drawRegion(canvas,getCachRegion(pTop,pBottom),cachPaint);//绘制并集
这里我们播放器更新缓冲进度都是缓冲时间所以才有上边的
//小于2s的都视为没有拖动
package com.stream.media.seekbar;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Region.Op;
import android.graphics.RegionIterator;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.SeekBar;
import com.zte.rtmpplayerdemo.R;
public class SeekBarExt extends SeekBar{
private Bitmap controlPointBitmap;//控制点图片
int seekBarBgHeight=12;//进度条背景宽度
Paint progressPaint;//进度条画笔
Paint bgPaint;//背景画笔
Paint cachPaint;//缓冲进度条画笔
int progressBarWidth=0;
int progressBarHeight=0;
private int lastCachProg=0;//secondProgress的上一次位置
private Region cachRegion;//缓冲进度条已缓冲区域
private Rect currentRect;//当前缓冲进度更新的一段距离
private float changeSizeScale;//全屏切换缩放比例
public SeekBarExt(Context context) {
super(context);
init(context);
}
public SeekBarExt(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SeekBarExt(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context){
controlPointBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.btn_control_points);
progressPaint=new Paint();
progressPaint.setColor(getResources().getColor(R.color.seekbar_progresscolor));
bgPaint=new Paint();
bgPaint.setColor(getResources().getColor(R.color.seekbar_bg));
cachPaint=new Paint();
cachPaint.setColor(getResources().getColor(R.color.seekbar_cachcolor));
}
@SuppressLint("DrawAllocation")
@Override
protected synchronized void onDraw(Canvas canvas) {
if(progressBarWidth!=0&&progressBarWidth!=getWidth()){//进度条大小是否改变
changeSizeScale=(float)getWidth()/(float)progressBarWidth;
}
progressBarWidth = getWidth();
progressBarHeight = getHeight();
int pTop=(progressBarHeight-seekBarBgHeight)/2;
int pBottom=(progressBarHeight-seekBarBgHeight)/2+seekBarBgHeight;
Drawable thumb=getThumb();
//绘制进度条背景
Rect bgRect = new Rect(0,pTop,progressBarWidth,pBottom);
canvas.drawRect(bgRect, bgPaint);
//绘制缓冲进度
drawCachProgress(canvas,progressBarWidth,pTop,pBottom);
//绘制播放进度
Rect progressRect = new Rect(0,pTop,thumb.getBounds().left,pBottom);
canvas.drawRect(progressRect, progressPaint);
//绘制控制点
canvas.drawBitmap(controlPointBitmap,thumb.getBounds().left,progressBarHeight/2-controlPointBitmap.getWidth()/2,null);
}
//计算绘制缓冲进度
private void drawCachProgress(Canvas canvas,int progressBarWidth,int pTop,int pBottom){
if(changeSizeScale!=0){//进度条尺寸变化了重新计算一遍已缓冲进度
Region region=getCachRegion(pTop,pBottom);
cachRegion=new Region(0, pTop,1, pBottom);
RegionIterator iter = new RegionIterator(region);
Rect r = new Rect();
while (iter.next(r)) {
r.set((int)(r.left*changeSizeScale), r.top,(int)(r.right*changeSizeScale), r.bottom);
cachRegion.op(r, Op.UNION);//求并集
}
changeSizeScale=0;
}
int secondProg=getSecondaryProgress();
float scale=(float)secondProg/(float)getMax();
if((secondProg-lastCachProg)>=0&&(secondProg-lastCachProg)<=2000){//小于2s的都视为没有拖动
if(currentRect==null){
currentRect= new Rect(0,pTop,(int)(scale*progressBarWidth),pBottom);
}
currentRect.right=(int)(scale*progressBarWidth);
}else{//手指拖动了 重新定位
if(currentRect!=null){
currentRect.left=(int)(scale*progressBarWidth);//定位到新的位置
currentRect.right=(int)(scale*progressBarWidth)+1;
}
}
lastCachProg=secondProg;
if(currentRect!=null){
getCachRegion(pTop,pBottom).op(currentRect, Op.UNION);//求并集
}
drawRegion(canvas,getCachRegion(pTop,pBottom),cachPaint);//绘制并集
}
//绘制并集
private void drawRegion(Canvas canvas,Region rgn,Paint paint)
{
RegionIterator iter = new RegionIterator(rgn);
Rect r = new Rect();
while (iter.next(r)) {
canvas.drawRect(r, paint);
}
}
//懒加载
private Region getCachRegion(int pTop,int pBottom) {
if(cachRegion==null){
cachRegion=new Region(0, pTop,1, pBottom);
}
return cachRegion;
}
}
seekbar.setProgress(videoPlayTime);//我们的播放器进度都是毫秒值
seekbar.setSecondaryProgress(iSeconds);//我们的播放器进度都是毫秒值
主要原理是利用Region不断的求并集 实现断断续续的效果,Region还有好多用法不断学习中。。。。。