最近要弄个播放器,但是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; } }
<com.stream.media.seekbar.SeekBarExt android:id="@+id/mediaPlayer_seekbar" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="5" android:layout_marginLeft="10dp" android:layout_marginRight="20dp" android:layout_gravity="center_vertical" android:max="100" android:progress="0" > </com.stream.media.seekbar.SeekBarExt>
seekbar.setProgress(videoPlayTime);//我们的播放器进度都是毫秒值
seekbar.setSecondaryProgress(iSeconds);//我们的播放器进度都是毫秒值
主要原理是利用Region不断的求并集 实现断断续续的效果,Region还有好多用法不断学习中。。。。。