最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

android實(shí)現(xiàn)錄屏小功能

 更新時(shí)間:2020年02月05日 09:39:32   作者:poorSir  
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)錄屏小功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了android實(shí)現(xiàn)錄屏小功能的具體代碼,供大家參考,具體內(nèi)容如下

思路

android實(shí)現(xiàn)錄屏功能有兩種方案,一種是直接使用android自帶的MediaProjectionManager實(shí)現(xiàn)錄屏功能,第二種是是只錄語音,用戶的操作通過某種方式進(jìn)行記錄保存,最后通過某種協(xié)議進(jìn)行播放。

兩種方案各有各的優(yōu)缺點(diǎn),前者實(shí)現(xiàn)方式簡(jiǎn)單,但無法只錄制特定區(qū)域的畫面,并且生成的視頻文件一般都比較大。后者實(shí)現(xiàn)較為繁瑣,音頻錄制android7.0之前沒有暫停方法,只能生成多個(gè)文件,然后對(duì)音頻進(jìn)行合成。用戶的操作需要自己進(jìn)行保存,播放時(shí)還原。播放器需要自定義生成。但后者的好處是可擴(kuò)展性高,支持特定區(qū)域錄制,并且生成的音頻文件比較小。

需求

錄制畫板,畫板要求可以更改顏色粗細(xì),可以擦除。畫板底部可以是白板,圖片。圖片要求是相機(jī)拍攝或者本地圖片。可以播放錄制內(nèi)容;需要上傳,所以文件要小,所有只能選擇第二種方式。
github地址

整個(gè)項(xiàng)目生成的是一個(gè)文件夾,文件夾中包含一個(gè)MP3文件,一個(gè)cw協(xié)議文件(存儲(chǔ)用戶的操作),圖片。整個(gè)畫板是一個(gè)recyclerView,item中包含一個(gè)涂鴉畫板,圖片控件。播放時(shí)讀取cw協(xié)議文件,按照時(shí)間一個(gè)個(gè)繪制,協(xié)議內(nèi)容包含畫板各個(gè)頁(yè)的內(nèi)容是空白畫板還是圖片,時(shí)間點(diǎn),操作(切換圖片/畫線)。

音頻

//開始錄音
  if (mMediaRecorder == null) {
      mMediaRecorder = new MediaRecorder();
    }
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
    mMediaRecorder.setOutputFile(mRecordFilePath);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//amr_nb格式頭部有6個(gè)字節(jié)的頭信息

    try {
      mMediaRecorder.prepare();
      mMediaRecorder.start();
      isRunning = true;
      AudioUtil.startAudio();
      mHandler.sendEmptyMessageDelayed(MSG_TYPE_COUNT_DOWN, 1000);
    } catch (IOException e) {
      e.printStackTrace();
    }
/**
   * 合成amr_nb編碼的音頻
   * @param partsPaths
   * @param unitedFilePath
   */
  public static void uniteAMRFile(List<String> partsPaths, String unitedFilePath) {
    try {
      File unitedFile = new File(unitedFilePath);
      FileOutputStream fos = new FileOutputStream(unitedFile);
      RandomAccessFile ra = null;
      for (int i = 0; i < partsPaths.size(); i++) {
        ra = new RandomAccessFile(partsPaths.get(i), "rw");
        if (i != 0) {
          ra.seek(6);
        }
        byte[] buffer = new byte[1024 * 8];
        int len = 0;
        while ((len = ra.read(buffer)) != -1) {
          fos.write(buffer,0,len);
        }
        File file = new File(partsPaths.get(i));
        if(file.exists()){
          file.delete();
        }
      }
      if(ra!=null){
        ra.close();
      }
      fos.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

音頻播放

mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(path);
    mediaPlayer.prepare();
   mediaPlayer.start();

recyclerView

是否禁止滑動(dòng)

public class ForbitLayoutManager extends LinearLayoutManager {
  private boolean canScrollHorizon = true;
  private boolean canScrollVertical = true;
  public ForbitLayoutManager(Context context) {
    super(context);
  }

  public ForbitLayoutManager(Context context, int orientation, boolean reverseLayout) {
    super(context, orientation, reverseLayout);
  }

  public ForbitLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }

  public void setCanScrollHorizon(boolean canScrollHorizon) {
    this.canScrollHorizon = canScrollHorizon;
  }

  public void setCanScrollVertical(boolean canScrollVertical) {
    this.canScrollVertical = canScrollVertical;
  }

  @Override
  public boolean canScrollHorizontally() {
    return canScrollHorizon && super.canScrollHorizontally();
  }

  @Override
  public boolean canScrollVertically() {
    return canScrollVertical && super.canScrollVertically();
  }
}

滑動(dòng)時(shí)只滑動(dòng)一頁(yè)類似viewPage

mPagerSnapHelper = new PagerSnapHelper();
mPagerSnapHelper.attachToRecyclerView(recyclerView);

獲得當(dāng)前是第幾頁(yè),類似viewPage的pageSelect

public class RecyclerViewPageChangeListenerHelper extends RecyclerView.OnScrollListener {
  private SnapHelper snapHelper;
  private OnPageChangeListener onPageChangeListener;
  private int oldPosition = -1;//防止同一Position多次觸發(fā)

  public RecyclerViewPageChangeListenerHelper(SnapHelper snapHelper, OnPageChangeListener onPageChangeListener) {
    this.snapHelper = snapHelper;
    this.onPageChangeListener = onPageChangeListener;
  }

  @Override
  public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    if (onPageChangeListener != null) {
      onPageChangeListener.onScrolled(recyclerView, dx, dy);
    }
  }

  @Override
  public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    int position = 0;
    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
    //獲取當(dāng)前選中的itemView
    View view = snapHelper.findSnapView(layoutManager);
    if (view != null) {
      //獲取itemView的position
      position = layoutManager.getPosition(view);
    }
    if (onPageChangeListener != null) {
      onPageChangeListener.onScrollStateChanged(recyclerView, newState);
      //newState == RecyclerView.SCROLL_STATE_IDLE 當(dāng)滾動(dòng)停止時(shí)觸發(fā)防止在滾動(dòng)過程中不停觸發(fā)
      if (newState == RecyclerView.SCROLL_STATE_IDLE && oldPosition != position) {
        oldPosition = position;
        onPageChangeListener.onPageSelected(position);
      }
    }
  }

  public interface OnPageChangeListener {
    void onScrollStateChanged(RecyclerView recyclerView, int newState);

    void onScrolled(RecyclerView recyclerView, int dx, int dy);

    void onPageSelected(int position);
  }
}

獲得當(dāng)前選擇的item(只能獲得可視頁(yè)面item)

View view = forbitLayoutManager.findViewByPosition(position);
  //有時(shí)會(huì)獲取到null,是因?yàn)轫?yè)面還沒有渲染完成,可以使用
  recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver
        .OnGlobalLayoutListener() {
      @Override
      public void onGlobalLayout() {
       //會(huì)多次調(diào)用,執(zhí)行完邏輯之后取消監(jiān)聽
          recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
      }
    });

根據(jù)時(shí)間進(jìn)行播放

 private void convertCWACT(CW cw, int seconds,boolean isSeek) {
    List<CWACT> cwacts = cw.getACT();
    //如何是播放器跳轉(zhuǎn),先回到首頁(yè),清空所有item中的畫板,防止從高時(shí)間跳轉(zhuǎn)到低時(shí)間出現(xiàn)錯(cuò)誤
    if(isSeek){
      position =0;
      forbitLayoutManager.scrollToPosition(position);
      forbitLayoutManager.setStackFromEnd(true);
      for(int i=0;i<recyclerViewList.size();i++){
        View view = recyclerViewList.get(i);
        if(view!=null){
          SimpleDoodleView doodleView = view.findViewById(R.id.doodleView);
          doodleView.clear();
        }
      }
    }
    for (CWACT cwact : cwacts) {
      int time = cwact.getTime();
      if(isSeek?time > seconds:time != seconds){
        continue;
      }
      if ("switch".equals(cwact.getAction())) {//切換頁(yè)面
        position = cwact.getCwSwitch().getIndex();
        forbitLayoutManager.scrollToPosition(position);
        forbitLayoutManager.setStackFromEnd(true);
      } else if ("line".equals(cwact.getAction())) {//劃線
        if(position>recyclerViewList.size()-1){
          continue;
        }
        View view = recyclerViewList.get(position);
        if(view!=null){
          SimpleDoodleView doodleView = view.findViewById(R.id.doodleView);
          doodleView.setDrawPath(cwact.getLine());
        }
      } else if ("clear".equals(cwact.getAction())) {//清屏
        if(position>recyclerViewList.size()-1){
          continue;
        }
        View view = recyclerViewList.get(position);
        if(view!=null){
          SimpleDoodleView doodleView = view.findViewById(R.id.doodleView);
          doodleView.clear();
        }
      }
    }
  }

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解Android的.aar文件生成方法以及使用技巧

    詳解Android的.aar文件生成方法以及使用技巧

    給大家詳細(xì)分析一下在Android中關(guān)于.aar文件生成的方法以及相關(guān)是使用技巧分析,需要的朋友學(xué)習(xí)參考下吧。
    2017-12-12
  • Android UI設(shè)計(jì)系列之自定義SwitchButton開關(guān)實(shí)現(xiàn)類似IOS中UISwitch的動(dòng)畫效果(2)

    Android UI設(shè)計(jì)系列之自定義SwitchButton開關(guān)實(shí)現(xiàn)類似IOS中UISwitch的動(dòng)畫效果(2

    這篇文章主要介紹了Android UI設(shè)計(jì)系列之自定義SwitchButton開關(guān)實(shí)現(xiàn)類似IOS中UISwitch的動(dòng)畫效果,具有一定的實(shí)用性和參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • 如何利用Flutter仿寫微信搜索頁(yè)效果

    如何利用Flutter仿寫微信搜索頁(yè)效果

    這篇文章主要給大家介紹了關(guān)于如何利用Flutter仿寫微信搜索頁(yè)效果的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-01-01
  • Android中.9.png圖片的使用及制作

    Android中.9.png圖片的使用及制作

    這篇文章主要介紹了Android中.9.png圖片的使用及制作的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-01-01
  • Android實(shí)現(xiàn)加載圈

    Android實(shí)現(xiàn)加載圈

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)加載圈,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 詳解Flutter中l(wèi)istview的高級(jí)用法

    詳解Flutter中l(wèi)istview的高級(jí)用法

    一般我們使用Listview的方式是構(gòu)建要展示的item,然后將這些item傳入ListView的構(gòu)造函數(shù)即可,通常情況下這樣做是夠用了,但是不排除我們會(huì)有一些其他的特殊需求。今天我們會(huì)來講解一下ListView的一些高級(jí)用法,希望對(duì)大家有所幫助
    2023-01-01
  • Android開發(fā)MediaCodec和lamemp3多段音頻截取拼接

    Android開發(fā)MediaCodec和lamemp3多段音頻截取拼接

    這篇文章主要為大家介紹了Android開發(fā)使用MediaCodec和lamemp3實(shí)現(xiàn)多段音頻截取拼接的編程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • Android證書安裝過程介紹

    Android證書安裝過程介紹

    大家好,本篇文章主要講的是Android證書安裝過程介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • Android下的POS打印機(jī)調(diào)用的簡(jiǎn)單實(shí)現(xiàn)

    Android下的POS打印機(jī)調(diào)用的簡(jiǎn)單實(shí)現(xiàn)

    本篇文章主要介紹了Android下的POS打印機(jī)調(diào)用的簡(jiǎn)單實(shí)現(xiàn),非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-04-04
  • Android獲取通話時(shí)間實(shí)例分析

    Android獲取通話時(shí)間實(shí)例分析

    我們知道安卓系統(tǒng)中通話時(shí)長(zhǎng)應(yīng)該是歸Callog管,所以建議去查查ContactProvider,或者是TelephonyProvider,本文也總結(jié)了一些,需要的朋友可以參考下
    2012-12-12

最新評(píng)論

泾川县| 昭觉县| 枣阳市| 米脂县| 南漳县| 乐陵市| 农安县| 上虞市| 闻喜县| 尉氏县| 临颍县| 河南省| 平阳县| 玛纳斯县| 吕梁市| 孟村| 沁源县| 三原县| 邹城市| 秭归县| 井冈山市| 和林格尔县| 仪征市| 霍州市| 盐亭县| 邵武市| 芜湖市| 迭部县| 厦门市| 福鼎市| 巴林右旗| 合肥市| 容城县| 合山市| 巴林左旗| 贺州市| 伊川县| 沙坪坝区| 克东县| 麻江县| 磐石市|