android视频缓冲进度条SeekBar有断断续续的间断效果

最近要弄个播放器,但是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);
	} 


2.绘制缓冲进度条,(播放进度、背景、控制点都是比较简单的方法实现不多说)。缓冲进度条就是要根据 getSecondaryProgress 进度 不断更新currentRect 的位置,(currentRect 标识上一次进度-----到----当前进度 的 距离) 每一次更新 这段距离 都与全局变量cachRegion求 并集 (就是把每段更新的距离都保存到cachRegion中)在一次性的画出cachRegion中的内容 这样可以保证无论怎么拖动进度条更新都是正确的会有断断续的效果

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.setMax(videoConutTime); //我们的播放器进度都是毫秒值

seekbar.setProgress(videoPlayTime);//我们的播放器进度都是毫秒值

seekbar.setSecondaryProgress(iSeconds);//我们的播放器进度都是毫秒值


主要原理是利用Region不断的求并集 实现断断续续的效果,Region还有好多用法不断学习中。。。。。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您想要实现自定义的视频播放进度条和暂停/播放按钮,可以按照以下步骤进行: 1. 在布局文件中添加 VideoView、SeekBar 和暂停/播放按钮: ``` <VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="wrap_content" /> <SeekBar android:id="@+id/seek_bar" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/play_pause_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Pause" /> ``` 2. 在 Activity 中获取 VideoView、SeekBar 和暂停/播放按钮的引用: ``` VideoView videoView = findViewById(R.id.video_view); SeekBar seekBar = findViewById(R.id.seek_bar); Button playPauseButton = findViewById(R.id.play_pause_button); ``` 3. 设置 VideoView 的路径并开始播放: ``` videoView.setVideoPath("path/to/video.mp4"); videoView.start(); ``` 4. 为 VideoView 添加一个 OnPreparedListener,当视频准备好时,设置 SeekBar 的最大值和添加一个定时器来更新 SeekBar进度: ``` videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { seekBar.setMax(videoView.getDuration()); final Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { seekBar.setProgress(videoView.getCurrentPosition()); handler.postDelayed(this, 1000); } }; handler.postDelayed(runnable, 1000); } }); ``` 5. 为 SeekBar 添加一个 OnSeekBarChangeListener,当拖动 SeekBar 时,改变视频播放的位置: ``` seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { videoView.seekTo(progress); } } @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) {} }); ``` 6. 为暂停/播放按钮添加一个 OnClickListener,当点击按钮时,暂停或继续播放视频: ``` playPauseButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (videoView.isPlaying()) { videoView.pause(); playPauseButton.setText("Play"); } else { videoView.start(); playPauseButton.setText("Pause"); } } }); ``` 7. 为 VideoView 添加一个 OnCompletionListener,当视频播放完成时,将暂停/播放按钮的文本设置为“Play”: ``` videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { playPauseButton.setText("Play"); } }); ``` 以上就是实现自定义视频播放进度条和暂停/播放按钮的方法。您可以根据您的需求自定义 SeekBar 的样式和暂停/播放按钮的图标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值