1. 程式人生 > >android 視訊錄製進度條(分段錄製,回滾刪除,類似美拍錄製)

android 視訊錄製進度條(分段錄製,回滾刪除,類似美拍錄製)

最近因為公司啟動微視訊專案,負責視訊錄製及視訊編輯這塊工作,而首先視訊錄製這塊需要支援分段錄製,和回滾刪除功能。

所以就做了這麼繼承View自定義了這個一個進度條小demo,有待完善及優化。

效果圖先出場

因為比較簡單加上有註釋,就不再多囉嗦,直接上程式碼了。

public class RecordProgressView extends View {

  // 最長錄製時間 和 最小錄製時間
  public final static float MAX_RECORD_TIME = 30000f;
  public final static float MIN_RECORD_TIME = 5000f;

  // 各種畫筆 進度 游標 最小時間標線 分段分割線 回滾
  private Paint progressPaint, flashPaint, minTimePaint, breakPaint, rollbackPaint;
  // 游標寬度
  private float flashWidth = 10f;
  // 最小時間標線寬度
  private float minTimeWidth = 5f;
  // 分段分割線寬度
  private float breakWidth = 2f;

  // 背景及各種畫筆顏色
  private int backgroundColor = Color.parseColor("#525252");
  private int progressColor = Color.parseColor("#86b00b");
  private int flashColor = Color.parseColor("#FFFFFF");
  private int minTimeColor = Color.parseColor("#FF0000");
  private int breakColor = Color.parseColor("#000000");
  private int rollbackColor = Color.parseColor("#e93c50");

  // 閃動游標是否可見
  private boolean isFlashVisible = true;
  // 游標繪製時間戳
  private long lastDrawFlashTime = 0;

  // 每次繪製完成後,進度條的長度
  private float countWidth = 0;
  private float perWidth;

  // 錄製片段
  private LinkedList<Integer> recordPartList = new LinkedList<>();
  private volatile RecordState currentState = RecordState.PAUSE;

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

  public RecordProgressView(Context paramContext, AttributeSet paramAttributeSet) {
    super(paramContext, paramAttributeSet);
    init();
  }

  public RecordProgressView(Context paramContext, AttributeSet paramAttributeSet, int paramInt) {
    super(paramContext, paramAttributeSet, paramInt);
    init();
  }

  private void init() {
    DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
    int screenWidth = displayMetrics.widthPixels;
    perWidth = screenWidth / MAX_RECORD_TIME;

    progressPaint = new Paint();
    flashPaint = new Paint();
    minTimePaint = new Paint();
    breakPaint = new Paint();
    rollbackPaint = new Paint();

    setBackgroundColor(backgroundColor);
    progressPaint.setColor(progressColor);
    flashPaint.setColor(flashColor);
    minTimePaint.setColor(minTimeColor);
    breakPaint.setColor(breakColor);
    rollbackPaint.setColor(rollbackColor);
  }

  /**
   * @description 更新錄製狀態
   */
  public void changeRecordState(RecordState state) {
    if (currentState == state) return;
    if (currentState != RecordState.START && state == RecordState.START && !recordPartList.isEmpty()) {
      recordPartList.add(recordPartList.getLast());
    }
    currentState = state;
    if (state == RecordState.DELETE) {
      if ((recordPartList != null) && (!recordPartList.isEmpty())) {
        recordPartList.removeLast();
      }
    }
  }

  public void resetProgress() {
    currentState = RecordState.PAUSE;
    recordPartList.clear();
  }

  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // onDraw是此自定義View的核心了
    int progressHeight = getMeasuredHeight();
    long currentTimeMillis = System.currentTimeMillis();
    countWidth = 0;
    // 繪製錄製片段和分割線
    if (!recordPartList.isEmpty()) {
      long previousTime = 0;
      long currentTime = 0;
      for (Integer aTimeList : recordPartList) {
        currentTime = aTimeList;
        float left = countWidth;
        countWidth += (currentTime - previousTime) * perWidth;
        canvas.drawRect(left, 0, countWidth - breakWidth, progressHeight, progressPaint);
        canvas.drawRect(countWidth - breakWidth, 0, countWidth, progressHeight, breakPaint);
        previousTime = currentTime;
      }
    }
    // 繪製最小時間分割線
    if (recordPartList.isEmpty()
        || (!recordPartList.isEmpty() && recordPartList.getLast() <= MIN_RECORD_TIME)) {
      float left = perWidth * MIN_RECORD_TIME;
      canvas.drawRect(left, 0, left + minTimeWidth, progressHeight, minTimePaint);
    }
    // 繪製回滾狀態
    if (currentState == RecordState.ROLLBACK) {
      long lastPartStartTime =
          recordPartList.size() > 1 ? recordPartList.get(recordPartList.size() - 2) : 0;
      long lastPartEndTime =
          recordPartList.size() > 0 ? recordPartList.get(recordPartList.size() - 1) : 0;
      float left = countWidth - (lastPartEndTime - lastPartStartTime) * perWidth;
      float right = countWidth;
      canvas.drawRect(left, 0, right, progressHeight, rollbackPaint);
    }
    // 繪製錄製進度
    if (currentState == RecordState.START) {
      canvas.drawRect(countWidth, 0, countWidth + flashWidth, getMeasuredHeight(), flashPaint);
    } else {
      // 如果當前不是錄製狀態的話 游標是閃動的 而閃動的時間是這裡800
      if (lastDrawFlashTime == 0 || currentTimeMillis - lastDrawFlashTime >= 800) {
        isFlashVisible = !isFlashVisible;
        lastDrawFlashTime = System.currentTimeMillis();
      }
      if (isFlashVisible) {
        canvas.drawRect(countWidth, 0, countWidth + flashWidth, getMeasuredHeight(), flashPaint);
      }
    }
    // 基於 Android 16毫秒 重新整理
    getHandler().postDelayed(invalidateRunnable, 16);
  }

  private Runnable invalidateRunnable = new Runnable() {
    @Override
    public void run() {
      switch (currentState) {
        case START: // 更新繪製進度
          if (recordPartList.size() > 0)
            recordPartList.add(recordPartList.removeLast() + 16);
          else
            recordPartList.add(16);
          break;
      }
      invalidate();
    }
  };

  public int getLastTime() {
    if ((recordPartList != null) && (!recordPartList.isEmpty())) {
      return recordPartList.getLast();
    }
    return 0;
  }

  public int getLastStartTime() {
    try {
      if ((recordPartList != null) && (!recordPartList.isEmpty())) {
        return recordPartList.get(recordPartList.size() - 2);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return 0;
  }

  public boolean isRecordEmpty() {
    return recordPartList.isEmpty();
  }

  /**
   * @description 視訊錄製的各種狀態
   */
  public enum RecordState {
    START(0x1), PAUSE(0x2), ROLLBACK(0x3), DELETE(0x4);
    private int value;

    RecordState(int intValue) {
      value = intValue;
    }

    int getValue() {
      return value;
    }
  }
}