手机qq里面发送小视频有个功能是,分段录制视频,就是录制的时候,可以停下来,然后再接着录。这个功能目前被我们的项目使用到了,于是,我就自定义了一个SeekBar,给录制视频,编辑视频,播放视频使用。
进度条主要包括两个部分:进度条和可以拖动的图片
和qq的进度条有点不同的是,我的进度条,到达100%的时候,是没有填充满的,看下图
我预留了一个图片的位置给剪切的那个图片。
当我滑动或者点击图片的时候,我们就要去编辑这几段视频了(图片中有5段视频),比如说我点击了一次剪切图片,就会变成下图:
图片中有白色的分割线,我们叫断点,每个断点就表示,之前在这个位置录视频的时候暂停过。大致功能就是这样啦。上代码吧
public class SeekVideoBar extends SeekBar implements GestureDetector.OnGestureListener {
private Bitmap controlPointBitmap;
Paint progressPaint;//绘制进度的笔
Paint bgPaint;//绘制进度条背景颜色的笔
Paint cachPaint;//绘制二级缓存的笔
Paint pointPaint;//绘制断点的笔
int progressBarWidth = 0;
int progressBarHeight = 0;//整个view的高度,一般情况是thumb的高度
int progressHeight = 12;//进度条的高度
private int state = 1;
public static final int STATE_MAKING = 0;
public static final int STATE_EDITING = 1;
public static final int STATE_PLAYING = 2;
private GestureDetector detector;
public SeekVideoBar(Context context) {super(context);init(context);}
public SeekVideoBar(Context context, AttributeSet attrs) {super(context, attrs);init(context);}
public SeekVideoBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
controlPointBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blank);
progressPaint = new Paint();
bgPaint = new Paint();
cachPaint = new Paint();
pointPaint = new Paint();
progressPaint.setColor(Color.parseColor("#ff1786EF"));
bgPaint.setColor(Color.parseColor("#90ffffff"));
cachPaint.setColor(Color.parseColor("#ffff0000"));
pointPaint.setColor(Color.parseColor("#ff000000"));
this.setOnSeekBarChangeListener(listener);
detector = new GestureDetector(context, this);}
@SuppressLint("DrawAllocation")@Override
protected synchronized void onDraw(Canvas canvas) {
progressBarWidth = getWidth();
progressBarHeight = getHeight();
int pTop = (progressBarHeight - progressHeight) / 2;
int pBottom = (progressBarHeight - progressHeight) / 2 + progressHeight;progressBarWidth = progressBarWidth - controlPointBitmap.getWidth();
Rect bgRect = new Rect(0, pTop, progressBarWidth + controlPointBitmap.getWidth(), pBottom);
canvas.drawRect(bgRect, bgPaint);//绘制背景,灰色部分
int sec = progressBarWidth * getSecondaryProgress() / 100;
Rect secProgressRect = new Rect(0, pTop, sec, pBottom);
canvas.drawRect(secProgressRect, cachPaint);//绘制二级缓存,红色部分
int imgLeft = progressBarWidth * currentProgress / 100;
Rect progressRect = new Rect(0, pTop, imgLeft, pBottom);
canvas.drawRect(progressRect, progressPaint);//绘制进度,蓝色部分
drawPoints(canvas, pTop, pBottom);//绘制断点
canvas.drawBitmap(controlPointBitmap, imgLeft, progressBarHeight / 2 - controlPointBitmap.getHeight() / 2, null);//绘制拖动图片
}
private Listpoints;
/* * 录制视频的是,可以分段录制,中间暂停的地方,会有一个Point断点 */
public void setPoints(Listpoints) {this.points = points;}
private void drawPoints(Canvas canvas, int pTop, int pBottom) {
if (points == null) {return;}
List tempPoints = new ArrayList();
tempPoints.addAll(points);
if (tempPoints.size() > 2) {
tempPoints.remove(0);//不绘制断点0
}
for (int progress : tempPoints) {
int point = progressBarWidth * progress / 100;
Rect bgRect = new Rect(point, pTop, point + 2, pBottom);
canvas.drawRect(bgRect, bgPaint);
}
invalidate();
}
public void setState(int state) {
this.state = state;
if (state == STATE_EDITING) {//
if (currentProgress < mSecondProgress) {
controlPointBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.video_cut_red);
} else {
controlPointBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.video_cut);
}
bgPaint.setColor(Color.parseColor("#90ffffff"));
cachPaint.setColor(Color.parseColor("#ffff0000"));
} else if (state == STATE_MAKING) {//
controlPointBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blank);
setSecondaryProgress(0);
} else {//
bgPaint.setColor(Color.parseColor("#ff000000"));
cachPaint.setColor(Color.parseColor("#90ffffff"));
controlPointBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blank);
}
invalidate();
}
private boolean isScroll = false;
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (state == STATE_EDITING) {//不是编辑阶段触碰无效
if (event.getAction() == MotionEvent.ACTION_UP && isScroll) {
//如果手指抬起来的时候,是滑动结束,就把事件给原生的seekbar处理
return super.onTouchEvent(event);
} else {
//剩下的情况,都把事件传递给手势
return detector.onTouchEvent(event);
}
} else {
return false;
}
}
private int BITMAP_STATE = 0;//0,表示normal;1表示cut
private int currentProgress;//当前的进度
private int mSecondProgress;//制作视频的时候的最大进度
private OnSeekBarChangeListener listener = new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
currentProgress = progress;
if (state == STATE_MAKING) {// 视频制作过程中
mSecondProgress = progress;
setSecondaryProgress(mSecondProgress);
return;
} else if (state == STATE_PLAYING) {// 视频播放过程中
return;
} else {// 编辑阶段
if (progress >= mSecondProgress) {
setProgress(mSecondProgress);//在编辑阶段,如果当前的进度,超过了我们的最大进度,就一直固定在最大进度
if(BITMAP_STATE == 0){//不需要每次都重新加载
controlPointBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.video_cut);
BITMAP_STATE = 1;
}
}else{
if(BITMAP_STATE == 1){//不需要每次都重新加载
controlPointBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.video_cut_red);
BITMAP_STATE = 0;
}
}
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//不是编辑状态无法继续
if (state != STATE_EDITING) {
return;
}
int index = 0;
int min = 100;
//点击或者滑动结束后,找到最近的断点,然后跳转过去
for (int i = 0; i < points.size(); i++) {
int progress = points.get(i);
int distance = Math.abs(progress - currentProgress);
if (min > distance) {
min = distance;
index = i;
}
}
cutBack(index);
}
};
private OnCutListener cutListener;
public void setOnCutListener(OnCutListener cutListener) {
this.cutListener = cutListener;
}
public interface OnCutListener {
public static final int KEEP_ALL = -1;
void onCut(int index);
}
@Override
public boolean onDown(MotionEvent arg0) {
isScroll = false;
return true;
}
@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
return false;
}
@Override
public void onLongPress(MotionEvent arg0) {
}
@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
isScroll = true;
return super.onTouchEvent(arg1);
}
@Override
public void onShowPress(MotionEvent arg0) {
}
@Override
public boolean onSingleTapUp(MotionEvent ev) {
//点击事件
int downX = (int) ev.getX();
int downY = (int) ev.getY();
int left = progressBarWidth * currentProgress / 100;
Rect r = new Rect(left, progressBarHeight / 2 - controlPointBitmap.getHeight() / 2, left + controlPointBitmap.getWidth(), progressBarHeight / 2 + controlPointBitmap.getHeight() / 2);
//如果点击的范围就是图片的范围,就跳转到前一个断点
if (r.contains(downX, downY)) {
//找到当前断点的index
int index = 0;
for (int i = 0; i < points.size(); i++) {
if(points.get(i) == currentProgress){
index = i;
}
}
//找到前一个断点
if(index == 0){
index = 0;
}else{
index = index - 1;
}
cutBack(index);
return true;
}
return super.onTouchEvent(ev);
}
private void cutBack(int index){
int progress = points.get(index );
setProgress(progress);
if (cutListener != null) {
if (index > points.size() - 2) {
cutListener.onCut(OnCutListener.KEEP_ALL);
} else {
cutListener.onCut(index);
}
}
}
}
在activity中这么使用
怎么贴代码的。。。好难看啊。。。里面注释还蛮多的,就不解释啦
或者去下载资源吧,csdn不用积分的。。。
http://download.csdn.net/detail/xiaodousa/9613484
---------------------------------分割线----------------------------------
在写这个自定义的seekbar我也遇到了问题,还望大神教我
seekbar里面的可以拖动的图片,的位置
getThumb().getBounds().left//表示那个图片的左边的坐标,可是每次都存在偏差;导致如果我绘制剪切的这个图片的时候,如果用这个left,就会不对;最后我改了方案,用了另外一个方式才实现的{getThumb()网上有重写了一个getSeekBarThumb()方法的,同时需要重写一下setThumb()}
canvas.drawBitmap(controlPointBitmap, imgLeft, progressBarHeight / 2 - controlPointBitmap.getHeight() / 2, null);//绘制拖动图片
如果我把上面的imgLeft换成getSeekBarThumb().getBounds().left就会出现偏差,不知道是什么原因
以上