模拟QQ多段录制视频,使用到的SeekBar

手机qq里面发送小视频有个功能是,分段录制视频,就是录制的时候,可以停下来,然后再接着录。这个功能目前被我们的项目使用到了,于是,我就自定义了一个SeekBar,给录制视频,编辑视频,播放视频使用。

进度条主要包括两个部分:进度条和可以拖动的图片

和qq的进度条有点不同的是,我的进度条,到达100%的时候,是没有填充满的,看下图


100%

我预留了一个图片的位置给剪切的那个图片。

当我滑动或者点击图片的时候,我们就要去编辑这几段视频了(图片中有5段视频),比如说我点击了一次剪切图片,就会变成下图:

保留剩下的4个小视频


保留0个视频

图片中有白色的分割线,我们叫断点,每个断点就表示,之前在这个位置录视频的时候暂停过。大致功能就是这样啦。上代码吧

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就会出现偏差,不知道是什么原因

以上

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容