Android视频裁剪自定义View

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/BlogRecord/article/details/54767797

功能需求:


有个视频裁剪功能,需要自定义View具体如下

1. 裁剪选择区域模块,可以自定义最少裁剪时间
2. 当选择低于最少裁剪时间时,再次滑动会自动推动左右选择轴,直至碰到边缘为止
3. 选择空白区域,并左右滑动时自动推动选择轴的位置
4. 可选控制(是否裁剪模式,是否显示播放进度,裁剪模式下(未选中的背景增加阴影图层),播放过的背景增加阴影图层等)
这里写图片描述

实现代码:


package com.play.pro.widgets;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import com.play.pro.R;
import com.play.pro.utils.ScreenUtils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.MediaMetadataRetriever;
import android.media.ThumbnailUtils;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 视频(缩略图、裁剪)进度滑动条
 */
public class VideoSeekBar extends View {

    /** 日志Tag */
    //private final String TAG = "VideoSeekBar";
    // ============== 其他变量 ===============
    /** 滑动的图片(左右两个) */
    private Bitmap leftBitmap, rightBitmap;
    // --
    /** dip转换px */
    private int dip = 0;
    /** 视频路径 */
    private String videoUri = null;
    /** 当前View 宽度 */
    private int vWidth;
    /** 当前View 高度 */
    private int vHeight;
    /** 关键帧时间 */
    private float videoFrame = 0f;
    /** 视频的总长度(毫秒) */
    private int videoDuration = 0;
    /** 当前播放的时间(毫秒) */
    private int videoPlayProgress = 0;
    /** 屏幕上坐标转换时间 - X轴 横 */
    private float xTime = -1f;
    // --
    /** 是否裁剪模式 */
    private boolean isCutMode = false;
    /** 是否清空内存 - 销毁资源*/
    private boolean isClearMemory = true;
    /** 是否绘制播放进度条 */
    private boolean isDrawProgressLine = false;
    /** 是否绘制播放进度背景 */
    private boolean isDrawProgressBG = false;
    // -- 画笔 --
    /** 绘制缩略图画笔 */
    private Paint thumbPaint = new Paint();
    /** 播放进度画笔 */
    private Paint progressPaint = new Paint();
    /** 播放进度背景(阴影层)画笔 */
    private Paint progressBgPaint = new Paint();
    // ============== 缩略图处理 ===============
    /** 缩略图数量 */
    private int thumbCount = 7;
    /** 缩略图Bitmap */
    private Bitmap[] thumbBitmaps;

    public VideoSeekBar(Context context) {
        super(context);
        init();
    }

    public VideoSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public VideoSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // --------------------
        // 绘制缩略图 - 防止进行销毁中,导致触发
        if (!isClearMemory && thumbBitmaps != null) {
            // 遍历缩略图数量
            for (int i = 0;i < thumbCount;i++) {
                if(isClearMemory){ // 如果正在回收中,则跳出方法
                    break;
                }
                if (thumbBitmaps[i] != null) {
                    try {
                        // 绘制缩略图
                        canvas.drawBitmap(thumbBitmaps[i], i * thumbBitmaps[i].getWidth(), 0, thumbPaint);
                    } catch (Exception e) {
                    }
                }
            }
        }
        // --------------------
        // 是否绘制播放进度背景(阴影层) - 裁剪模式下滑动也会有这个阴影,所以需要加上是否裁剪模式处理
        if (!isCutMode && isDrawProgressBG){
            // 计算时间防止等于-1 、 防止获取高度失败
            if (getViewWidthConvertTime() != -1f && vHeight != 0){
                // 转换当前的X轴位置(播放进度 / 每个X轴对应的时间)
                float convX = ((float) videoPlayProgress) / xTime;
                // 如果大于等于View的宽度重新设置
                if(convX + dip >= vWidth){
                    // 重置位置,直接到结尾
                    convX = vWidth - (int) (dip * 1.5);
                }
                // 绘制一个矩形
                canvas.drawRect(0, 0, convX + (dip / 2), vHeight, progressBgPaint);
            }
        }
        // --------------------
        // 是否绘制播放进度条
        if (isDrawProgressLine){
            // 计算时间防止等于-1 、 防止获取高度失败
            if (getViewWidthConvertTime() != -1f && vHeight != 0){
                // 转换当前的X轴位置(播放进度 / 每个X轴对应的时间)
                float convX = ((float) videoPlayProgress) / xTime;
                // 如果大于等于View的宽度重新设置,防止线条回弹(vWidth - convX < dip 导致下次会大于vWidth,线条会回弹)
                if(convX + dip >= vWidth){
                    // 重置位置,直接到结尾,显示一条线
                    convX = vWidth - (int) (dip * 1.5);
                }
                // 绘制一个矩形(一条线)
                canvas.drawRect(convX, 0, convX + (dip / 2), vHeight, progressPaint);
            }
        }
        // --------------------
        // 判断是否裁剪模式, 并且高度不等于0,防止计算出现问题
        if (isCutMode && vHeight != 0){
            // 计算右边边距值
            reckonRightSX();
            // 绘制左边滑动的X轴位置
            canvas.drawBitmap(leftBitmap, leftSX, 0, thumbPaint);
            // 绘制右边滑动的X轴位置
            canvas.drawBitmap(rightBitmap, rightSX, 0, thumbPaint);
            // === 绘制左边拖动阴影图层 ===
            if (leftSX != 0f){
                // 绘制一个矩形
                canvas.drawRect(0, 0, leftSX, vHeight, progressBgPaint);
            }
            // === 绘制右边拖动阴影图层 ===
            if (rightSX != rightMarginX){
                // 绘制一个矩形
                canvas.drawRect(rightSX + sliderIgWidth, 0, vWidth, vHeight, progressBgPaint);
            }
        }
    }

    // ===================== 

    // --
    /** 右边的边距(间距图片宽度) */
    private float rightMarginX = 0f;
    /** 左边滑动的X轴 */
    private float leftSX = 0f;
    /** 右边滑动的X轴 */
    private float rightSX = 0f;
    /** 滑动的图片宽度 */
    private int sliderIgWidth = 0;
    // ===
    /** 上次滑动的值 */
    private float oTouchX = -1f;
    /** 旧的中间值 */
    private float lrMiddleX = -1f;
    /** 滑动的View*/
    private int touchView = -1;
    /** 滑动左边的View */
    private final int TOUCH_LEFT_VIEW = 1;
    /** 滑动右边的View */
    private final int TOUCH_RIGHT_VIEW = 2;
    /** 滑动左右两边中间空白部分 */
    private final int TOUCH_MIDST_VIEW = 3;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        // 属于裁剪模式才进行处理
        if(isCutMode){
            // 滑动中的X轴位置
            float xMove = event.getX();
            // --
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: // 按下时
                // 这样判断是刚好在之间,为了增加触摸体验,增加多一般的边距触摸优化
                //if (xMove >= leftSX && xMove <= (leftSX + sliderIgWidth))
                // --
                if (xMove >= (leftSX - sliderIgWidth / 2) && xMove <= (leftSX + ((float) sliderIgWidth) * 1.5)){
                    touchView = TOUCH_LEFT_VIEW;
                    // 计算滑动距离
                    reckonSlide(xMove);
                } else if (xMove >= (rightSX - sliderIgWidth / 2) && xMove <= (rightSX + ((float) sliderIgWidth) * 1.5)){
                    touchView = TOUCH_RIGHT_VIEW;
                    // 计算滑动距离
                    reckonSlide(xMove);
                } else if (xMove >= (leftSX + sliderIgWidth) && xMove <= (rightSX + sliderIgWidth)){ // 属于滑动两个View中间模块
                    touchView = TOUCH_MIDST_VIEW;
                    // 计算滑动距离
                    reckonSlide(xMove);
                } else {  // 表示都没操作
                    lrMiddleX = oTouchX = touchView = -1;
                }
                break;
            case MotionEvent.ACTION_MOVE: // 滑动中
                // 计算滑动距离
                reckonSlide(xMove);
                break;
            case MotionEvent.ACTION_UP: // 抬起时
                lrMiddleX = oTouchX = touchView = -1;
                break;
            }
        }
        return true;
    }

    /** 计算右边的值 */
    private void reckonRightSX(){
        if(rightMarginX == 0f){
            rightMarginX = vWidth - sliderIgWidth;
        }
        if(rightSX == 0f){ // 默认值为0则表示为最尾端
            rightSX = rightMarginX;
        }
    }

    /**
     * 计算滑动
     * @param xMove 滑动的X轴
     */
    private void reckonSlide(float xMove){
        // 计算右边边距值
        reckonRightSX();
        // 如果都不属于滑动,则不处理
        if(!(touchView == TOUCH_LEFT_VIEW || touchView == TOUCH_RIGHT_VIEW
                || touchView == TOUCH_MIDST_VIEW)){
            return;
        }
        // 转换关键帧相差的X轴位置(关键帧时间 / 每个X轴对应的时间)
        float convX = videoFrame / xTime;
        // 计算间隔宽度(判断是滑动图片宽度大还是关键帧宽度大)
        float spacing = (convX > sliderIgWidth) ? convX : sliderIgWidth;
        // --
        if(touchView == 1){ // 属于滑动左边图片
            // 虚拟位置 = 滑动位置 + 间距宽度
            float vX = xMove + spacing;
            // 判断是否滑动会推动到右边
            if(vX > rightSX){
                // 如果已经给推到边缘了,则进行控制
                if (rightSX >= rightMarginX){
                    // 设置右边到边缘
                    rightSX = rightMarginX;
                    // 左边 = 右边 - 间距宽度(防止重叠)
                    leftSX = rightSX - spacing;
                } else { // 如果不在边缘,则进行推
                    leftSX = xMove;
                    rightSX = xMove + spacing;
                }
            } else { // 如果小于则表示没有触碰到
                leftSX = xMove;
                // 如果边距小于一半则滑动到底部 + 3分之1的边距
                if (xMove <= sliderIgWidth / 2 + sliderIgWidth / 3){
                    leftSX = 0f;
                }
            }
            // 最后再进行判断多一次,防止出现意外(快速滑动)
            adjustLoc(TOUCH_LEFT_VIEW, spacing);
        } else if (touchView == 2){ // 属于滑动右边图片
            // 判断是否滑动到边缘(右侧边缘)
            if(xMove >= rightMarginX){ // 滑动到边缘则直接设置边缘
                rightSX = rightMarginX;
            } else {
                // 判断是否触碰到左边 -> 滑动的距离 - 左边的位置 > 边距,表示没触碰
                if (xMove - leftSX > spacing){
                    rightSX = xMove;
                } else { // 如果触碰了
                    if (leftSX <= 0){ // 如果左边已经到了边缘
                        // 设置左边到边缘
                        leftSX = 0f;
                        // 右边 = 间距宽度
                        rightSX = spacing;
                    } else { // 左边没到边缘,则进行推
                        rightSX = xMove;
                        leftSX = rightSX - spacing;
                    }
                }
            }
            // 最后再进行判断多一次,防止出现意外(快速滑动)
            adjustLoc(TOUCH_RIGHT_VIEW, spacing);
        } else if (touchView == 3){ // 属于滑动两个View 中间空白的
            // 左右两个的间隔 = 右边减去左边(左边坐标 + 图片宽度)
            float lrSpace = rightSX - leftSX;
            if (lrMiddleX == -1f){
                // 获取中间值
                lrMiddleX = lrSpace;
            }
            // 判断滑动方向
            if (oTouchX == -1f){
                // 记录上次的滑动值
                oTouchX = xMove;
                return;
            }
            if (lrMiddleX > 0){
                // 判断左边是否已经到达最右边
                if(rightSX > rightMarginX){ // 如果已经给推到边缘了,则进行控制
                    adjustLoc(TOUCH_MIDST_VIEW, lrMiddleX); // 调整位置
                } else if (leftSX < 0){ // 如果左边的距离等于0
                    adjustLoc(TOUCH_MIDST_VIEW, lrMiddleX); // 调整位置
                } else { // 同步位移
                    // 判断滑动方向
                    if (xMove > oTouchX){ // 往右边滑动
                        if (rightSX < rightMarginX){
                            rightSX = rightSX + (xMove - oTouchX);
                            // --
                            leftSX = rightSX - lrMiddleX;
                        }
                    } else if (xMove < oTouchX){ // 往左边滑动
                        if (leftSX > 0){
                            leftSX = leftSX - (oTouchX - xMove);
                            // --
                            rightSX = leftSX + lrMiddleX;
                        }
                    }
                    // 记录上次的滑动值
                    oTouchX = xMove;
                    // 调整位置
                    adjustLoc(TOUCH_MIDST_VIEW, lrMiddleX);
                }
            }
        }
        // 进行绘制
        invalidate();
    }

    /**
     * 调整位置(防止左右超出边缘边距)
     * @param touchView 滑动的View
     * @param spacing 两个View间隔的边距
     */
    private void adjustLoc(int touchView, float spacing){
        // 判断左边是否到达边缘
        if (leftSX <= 0){
            // 设置左边到边缘
            leftSX = 0f;
            // 右边 = 间距宽度
            float tRightSX = spacing;
            // 判断当前位置是否大于边距
            if (rightSX < tRightSX){
                rightSX = tRightSX;
            }
        }
        // --
        // 判断右边是否到达边缘
        if (rightSX >= rightMarginX){
            // 设置右边到边缘
            rightSX = rightMarginX;
            // 左边 = 右边 - 间距宽度(防止重叠)
            float tLeftSX = rightSX - spacing;
            // 判断当前位置是否大于计算出来的位置
            if (leftSX > tLeftSX){
                leftSX = tLeftSX;
            }
        }
    }

    // ===========================================

    /**
     * 初始化操作
     */
    private void init(){
        // 防止不进行绘画 触发onDraw
        setWillNotDraw(false);
        // 获取左右两个滑动的图片
        leftBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.ic_slider_left);
        rightBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.ic_slider_right);
        // 先保存滑动图片宽度 
        sliderIgWidth = leftBitmap.getWidth();
        // 1 dip 对应的px
        dip = ScreenUtils.dipConvertPx(getContext(), 1.0f);
        // 初始化画笔
        initPaint();
    }

    /**
     * 初始化画笔
     */
    private void initPaint(){
        // 初始化画笔
        thumbPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 缩略图
        progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 播放进度 白色竖直线条
        progressBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 播放进度背景,半透明(画布遮挡层)
        // 画笔颜色
        progressPaint.setColor(Color.rgb(255, 255, 255)); // 字体颜色 - 白色
        progressBgPaint.setColor(Color.rgb(0, 0, 0)); // 背景进度颜色(画布遮挡层)
        // 设置透明度
        progressBgPaint.setAlpha(60); // 画布遮挡层
        // 设置画笔大小
        progressPaint.setStrokeWidth(dip * 2); // 线条
        // 设置画笔样式
        progressPaint.setStyle(Paint.Style.STROKE); // 设置粗线 - 线条
    }

    // ============== 内部计算方法  ==============

    /**
     * 获取View的宽度,转换对应的坐标值 = 时间
     * @return
     */
    private float getViewWidthConvertTime(){
        if(xTime == -1f){
            if(vWidth != 0 && videoDuration != 0){
                // 视频总进度 / 宽度 = 每个坐标占用多少毫秒
                xTime = videoDuration / vWidth;
            }
        }
        return xTime;
    }

    /**
     * 获取滑动图片
     * @param isLeft
     * @return
     */
    private Bitmap getSliderBitmap(boolean isLeft){
        // 防止高度为0
        if(vHeight != 0){
            // 获取高度进行计算
            int bHeight = leftBitmap.getHeight();
            // 判断是否需要缩放,高度不一直则要求缩放
            if (bHeight != vHeight){
                // 获取图片宽度
                int bWidth = leftBitmap.getWidth();
                // 计算宽度比例
                bWidth = (int) (((float) vHeight / (float) bHeight) * bWidth);
                // 保存缩放比例后的宽度
                sliderIgWidth = bWidth;
                // 进行比例缩放图片
                leftBitmap = Bitmap.createScaledBitmap(leftBitmap, bWidth, vHeight, true);
                rightBitmap = Bitmap.createScaledBitmap(rightBitmap, bWidth, vHeight, true);
            }
        }
        return isLeft ? leftBitmap : rightBitmap;
    }

    // ============== 内部处理方法  ==============

    /** 回收缩略图内存 */
    private void clearThumbs(){
        // 销毁资源中
        isClearMemory = true;
        // --
        if(thumbBitmaps != null){
            for(int i = 0, c = thumbBitmaps.length;i < c;i++){
                Bitmap bitmap = thumbBitmaps[i];
                if(bitmap != null){
                    if(bitmap != null && !bitmap.isRecycled()){
                        try {
                            bitmap.recycle();   
                        } catch (Exception e) {
                        }
                    }
                    bitmap = null;
                }
            }
        }
    }

    /** 创建缩略图 */
    private void buildThumbs(){
        // 先回收旧的内容
        clearThumbs();
        // 重新绘制进行刷新
        postInvalidate();
        // 判断路径是否为null
        if(!TextUtils.isEmpty(videoUri)){
            // 开启后台线程,生成缩略图
            new Thread(btRunn).start();
        }
    }

    /** 生成缩略图(来自本地视频) */
    private void buildThumbsToLocal(){
        // 进行创建缩略图(非回收)
        isClearMemory = false;
        // 设置Media构造器
        MediaMetadataRetriever mediaRetriever = new MediaMetadataRetriever();
        try {
            // 防止两个都为默认值
            while(vWidth == 0 || vHeight == 0){
                vWidth = getWidth();
                vHeight = getHeight();
            }
            // 计算每个图片的宽度(宽度 / 总数)
            int btWidth = vWidth / thumbCount;
            // 图片的高度
            int btHeight = vHeight;
            // 设置视频的路径
            mediaRetriever.setDataSource(videoUri);
            // 取得视频的长度(单位为毫秒)
            String vTime = mediaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
            // 保存视频总长度(毫秒)
            setVideoDuration(Integer.valueOf(vTime));
            // 进行计算滑动的边距
            getSliderBitmap(true);
            // 计算右边边距值
            reckonRightSX();
            // 获取View的宽度,转换对应的坐标值 = 时间
            getViewWidthConvertTime();
            // 转换时间,然后平分,设置缩略图时间间隔
            int interValSec = Integer.valueOf(vTime) / thumbCount;
            // 初始化缩略图容器
            thumbBitmaps = new Bitmap[thumbCount];
            // 遍历生成缩略图
            for (int i = 0;i < thumbCount;i++) {
                // 计算时间(秒数)
                long timeUs = i * interValSec * 1000;
                // 获取生成缩略图
                Bitmap bitmap = mediaRetriever.getFrameAtTime(timeUs, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
                // 保存缩略图
                thumbBitmaps[i] =  ThumbnailUtils.extractThumbnail(bitmap,  btWidth, btHeight, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
                // 刷新界面
                postInvalidate();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放构造器资源
                mediaRetriever.release();
            } catch (Exception e2) {
            }
        }
    }

    /** buildThumbs Runnable 创建缩略图线程 */
    private Runnable btRunn = new Runnable() {
        @Override
        public void run() {
            // 获取文件路径
            File file = new File(videoUri);
            // 判断是否本地文件
            if(file.exists()){
                buildThumbsToLocal();
            }
        }
    };

    /**
     * 设置视频的总长度(内部处理 - MediaMetadataRetriever 获取) - 毫秒
     * @param videoDuration
     */
    private void setVideoDuration(int videoDuration){
        this.videoDuration = videoDuration;
    }


    // ============== 内部控制代码 ===============
    /** 专门刷新View */
    private Handler vhandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what){
            case 0: // 正常进行绘制触发
                postInvalidate();
                break;
            case 1: // 满一秒进行触发
                displayTime = displayTime + 1000; // 累积时间
//              if(rtCallBack != null){
//                  rtCallBack.preSecond(displayTime);
//              }
                break;
            }
        }
    };

    /** 设备连接定时器 */
    private Timer refTimer;
    /** 设备连接定时器任务栈 */
    private TimerTask refTask;
    /** 整秒统计 */
    private int iTime = 0;
    /** 刷新时间(毫秒) */
    private int refTime = 500; // 250
    /** 刷新频率 1000 / 刷新时间 */
    private int refRate = 1000 / refTime;
    /** 对外获取时间 */
    private long displayTime = 0l;

    /**
     * 设置定时器,刷新View
     * @param isOpen 是否打开
     */
    private void setTimer(boolean isOpen) {
        if (isOpen) {
            try {
                if (refTimer != null) {
                    refTimer.cancel();
                    refTimer = null;
                }
                if (refTask != null) {
                    refTask.cancel();
                    refTask = null;
                }
            } catch (Exception e) {
            }
            // 开启定时器
            refTimer = new Timer(); // 每次重新new 防止被取消
            // 重新生成定时器 防止出现TimerTask is scheduled already 所以同一个定时器任务只能被放置一次
            refTask = new TimerTask() {
                @Override
                public void run() {
                    // 累加播放时间
                    videoPlayProgress += refTime;
                    // 如果大于总时间则进行重置
                    if(videoDuration != 0 && videoPlayProgress > videoDuration){
                        videoPlayProgress = videoDuration;
                        // 进行通知最后一次
                        vhandler.sendEmptyMessage(0);
                        // 并且关闭定时器
                        setTimer(false);
                        return;
                    }
                    // --
                    vhandler.sendEmptyMessage(0);
                    ++ iTime;
                    if(iTime >= refRate){
                        vhandler.sendEmptyMessage(1);
                        iTime = 0; // 满1秒
                    }
                }
            };
            // xx秒后执行,每隔xx秒再执行一次
            refTimer.schedule(refTask, 0, refTime); // 开启定时器
        } else {
            try {
                if (refTimer != null) {
                    refTimer.cancel();
                    refTimer = null;
                }
                if (refTask != null) {
                    refTask.cancel();
                    refTask = null;
                }
            } catch (Exception e) {
            }
            vhandler.sendEmptyMessage(0);
        }
    }

    // ============== 对外公开方法 ===============

    /**
     * 销毁操作方法
     */
    public void destroy(){
        clearThumbs();
    }

    /**
     * 进行重置
     */
    public void reset(){
        leftSX = 0f; // 重置到最左边
        rightSX = 0f; // 重置到最右边
    }

    /**
     * 是否允许裁剪(判断是否拖动)
     * @return
     */
    public boolean isTrimVideo(){
        if(leftSX != 0f || (rightSX != rightMarginX && rightSX != 0f && rightMarginX != 0f)){
            return true;
        }
        return false;
    }

    /**
     * 获取开始时间(左边X轴转换时间) - 毫秒
     * @return
     */
    public float getStartTime(){
        if(getViewWidthConvertTime() != -1){
            return leftSX * xTime;
        }
        return -1f;
    }

    /**
     * 获取结束时间(右边X轴转换时间) - 毫秒
     * @return
     */
    public float getEndTime(){
        if(getViewWidthConvertTime() != -1){
            return rightSX * xTime;
        }
        return -1f;
    }

    /**
     * 设置视频进度条
     * @param isCutMode 是否裁剪模式
     * @param videoUri 视频路径
     */
    public void setVideoUri(boolean isCutMode, String videoUri) {
        setVideoUri(isCutMode, videoUri, -1f);
    }

    /**
     * 设置视频进度条
     * @param isCutMode 是否裁剪模式
     * @param videoUri 视频路径
     * @param videoFrame 关键帧时间(毫秒)
     */
    public void setVideoUri(boolean isCutMode, String videoUri, float videoFrame) {
        this.setCutMode(isCutMode);
        this.videoUri = videoUri;
        this.videoFrame = videoFrame;
        // --
        // 生成缩略图
        buildThumbs();
    }

    /**
     * 设置当前播放进度
     * @param curTime 当前的时间(毫秒)
     */
    public void setProgress(int curTime){
        this.videoPlayProgress = curTime;
    }

    /**
     * 是否绘制播放进度条
     * @param isDrawProgressLine
     */
    public void setProgressLine(boolean isDrawProgressLine){
        this.isDrawProgressLine = isDrawProgressLine;
        // 判断是否需要开启定时器
        setTimer(this.isDrawProgressLine || this.isDrawProgressBG);
    }

    /**
     * 是否绘制播放进度背景
     * @param isDrawProgressBG
     */
    public void setProgressBG(boolean isDrawProgressBG){
        this.isDrawProgressBG = isDrawProgressBG;
        // 判断是否需要开启定时器
        setTimer(this.isDrawProgressLine || this.isDrawProgressBG);
    }

    /**
     * 设置进度绘制相关功能(统一是否显示)
     * @param isDrawProgress
     */
    public void setProgressDraw(boolean isDrawProgress){
        this.isDrawProgressLine = isDrawProgress;
        this.isDrawProgressBG = isDrawProgress;
        // 判断是否需要开启定时器
        setTimer(isDrawProgress);
    }

    /**
     * 设置裁剪模式
     * @param isCutMode 是否裁剪
     */
    public void setCutMode(boolean isCutMode){
        this.isCutMode = isCutMode;
        // 如果属于裁剪模式,则不绘制背景阴影
        if (isCutMode){
            this.isDrawProgressBG = false;
        }
    }

    /**
     * 设置裁剪模式
     * @param isCutMode 是否裁剪
     * @param isDrawProgressLine
     */
    public void setCutMode(boolean isCutMode, boolean isDrawProgressLine){
        this.setCutMode(isCutMode);
        // --
        this.isDrawProgressLine = isDrawProgressLine;
        // 判断是否需要开启定时器
        setTimer(isDrawProgressLine);
    }
}

使用方法(项目内有):


这里写图片描述

代码下载


Android视频裁剪自定义View

猜你喜欢

转载自blog.csdn.net/BlogRecord/article/details/54767797