思路

android实现录屏功能有两种方案,一种是直接使用android自带的MediaProjectionManager实现录屏功能,第二种是是只录语音,用户的操作通过某种方式进行记录保存,最后通过某种协议进行播放。
两种方案各有各的优缺点,前者实现方式简单,但无法只录制特定区域的画面,并且生成的视频文件一般都比较大。后者实现较为繁琐,音频录制android7.0之前没有暂停方法,只能生成多个文件,然后对音频进行合成。用户的操作需要自己进行保存,播放时还原。播放器需要自定义生成。但后者的好处是可扩展性高,支持特定区域录制,并且生成的音频文件比较小。

需求

录制画板,画板要求可以更改颜色粗细,可以擦除。画板底部可以是白板,图片。图片要求是相机拍摄或者本地图片。可以播放录制内容;需要上传,所以文件要小,所有只能选择第二种方式。
github地址

整个项目生成的是一个文件夹,文件夹中包含一个MP3文件,一个cw协议文件(存储用户的操作),图片。整个画板是一个recyclerView,item中包含一个涂鸦画板,图片控件。播放时读取cw协议文件,按照时间一个个绘制,协议内容包含画板各个页的内容是空白画板还是图片,时间点,操作(切换图片/画线)。

音频

//开始录音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个字节的头信息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

是否禁止滑动

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;}@Overridepublic boolean canScrollHorizontally() {return canScrollHorizon && super.canScrollHorizontally();}@Overridepublic boolean canScrollVertically() {return canScrollVertical && super.canScrollVertically();}
}

滑动时只滑动一页类似viewPage

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

获得当前是第几页,类似viewPage的pageSelect

public class RecyclerViewPageChangeListenerHelper extends RecyclerView.OnScrollListener {private SnapHelper snapHelper;private OnPageChangeListener onPageChangeListener;private int oldPosition = -1;//防止同一Position多次触发public RecyclerViewPageChangeListenerHelper(SnapHelper snapHelper, OnPageChangeListener onPageChangeListener) {this.snapHelper = snapHelper;this.onPageChangeListener = onPageChangeListener;}@Overridepublic void onScrolled(RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);if (onPageChangeListener != null) {onPageChangeListener.onScrolled(recyclerView, dx, dy);}}@Overridepublic void onScrollStateChanged(RecyclerView recyclerView, int newState) {super.onScrollStateChanged(recyclerView, newState);int position = 0;RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();//获取当前选中的itemViewView view = snapHelper.findSnapView(layoutManager);if (view != null) {//获取itemView的positionposition = layoutManager.getPosition(view);}if (onPageChangeListener != null) {onPageChangeListener.onScrollStateChanged(recyclerView, newState);//newState == RecyclerView.SCROLL_STATE_IDLE 当滚动停止时触发防止在滚动过程中不停触发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);}
}

获得当前选择的item(只能获得可视页面item)

    View view = forbitLayoutManager.findViewByPosition(position);//有时会获取到null,是因为页面还没有渲染完成,可以使用recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {//会多次调用,执行完逻辑之后取消监听recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);}});

根据时间进行播放

 private void convertCWACT(CW cw, int seconds,boolean isSeek) {List<CWACT> cwacts = cw.getACT();//如何是播放器跳转,先回到首页,清空所有item中的画板,防止从高时间跳转到低时间出现错误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())) {//切换页面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();}}}}

android录屏功能相关推荐

  1. Android 录屏功能的实现

    最近开发中,要实现录屏功能,查阅相关资料,发现调用 MediaProjectionManager的api 实现录屏功能即可: import android.Manifest; import andro ...

  2. android录屏功能的实现

    近期项目需要录屏功能,功能已实现,特此记录一下. //<----------------------------------录屏开始------------------------------- ...

  3. android 手机录屏功能,Android录屏功能的实现

    最近做一个Android开发的项目用到了录屏的功能,开始查阅了一些资料和博客,基本上都是在讨论ROOT的.直到后来在github上看到一个比较新的代码,才恍然发现,Android 5.0时候开放了一个 ...

  4. 如何调用android录屏功能吗,Android录屏功能的实现

    最近做一个Android开发的项目用到了录屏的功能,开始查阅了一些资料和博客,基本上都是在讨论ROOT的.直到后来在github上看到一个比较新的代码,才恍然发现,Android 5.0时候开放了一个 ...

  5. webRTC(二十一):android 录屏功能

    效果 录屏和截屏的思路基本一致,请看详细代码 布局 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/an ...

  6. 【Android】录屏功能实现——MediaProjection

    目录 Android录屏功能实现-MediaProjection 概述 工具类 作用 过程 权限申请 连接服务 开始录制 停止录制 总结 不积跬步,无以至千里:不积小流,无以成江海.要沉下心来,诗和远 ...

  7. android 实现手机录屏功能,基于MediaProjection实现Android移动手机截屏和录屏功能

    Android软件应用经常要求实现截屏和录屏的功能,那么如何实现Android软件截屏和录屏功能呢?本文将介绍基于MediaProjection实现Android移动手机截屏和录屏功能. MediaP ...

  8. Android 和dialog 防录屏功能失效,游戏防录屏功能失效.

    1. 正常禁止录屏在Activity的onCreate()方法中调用如下代码,但是在小米,OPPO等设备上只能禁止截屏,无法禁止录屏. @Overrideprotected void onCreate ...

  9. android 手机录屏功能,手机自带录屏功能在哪里找?轻松搞定屏幕录制

    手机的录屏功能如何使用?智能手机发展到现在,除了无线通话功能.讯息发送功能之外,又逐渐发展出拍照功能.上网功能.各类应用交互功能.尤其近几年在手机上看视频成为打发碎片化时间的重要消遣,在手机上录屏的需 ...

最新文章

  1. 格莱泽检验matlab,计量经济学实验指导书
  2. Flask基础知识点1
  3. access开发内销核算系统
  4. iReport工具的使用(三)
  5. 理解Caffe的网络模型
  6. proxychains-ng 工作原理分析
  7. mysql命令行的几个用法
  8. python 列表 remove()函数使用详解
  9. 12c rman中输入sql命令
  10. 强者不能恒强,偏向虎山行
  11. 第四章表单与文件-笔记-验证
  12. javaScript,Dwr分页模拟
  13. WINCC冗余、上位机冗余详细教程
  14. ConfuserEx 脱壳软件 使用教程
  15. 能源DEA--对于业务和环境评估的规模报酬与规模损害
  16. 微信小程序如何实现点击链接跳转到手机自带浏览器
  17. 【信号与系统】如何求系统的冲激响应和阶跃响应
  18. Altium Designer 21 安装教程
  19. xp cmd命令大全
  20. 腾讯《活着》频道JS图片轮换效果解析

热门文章

  1. 三星i718的优缺点
  2. AutoCAD学习笔记——常用快捷方式及家装设计相关概念
  3. 小程序制作海报并分享到朋友圈
  4. Spring入门详解
  5. PTA 藏尾诗 (20分)
  6. 微信号修改功能正式上线,网友:等你好久了!
  7. 【机器学习】11、贝叶斯网络
  8. bison进行语法分析学习记录
  9. 【TransCad】采用重力模型法实现交通分布预测
  10. Dwg文件怎么转换成pdf文件格式