最近在做一款视频剪辑的app时,基本每个功能都会有视频播放的功能,所以利用MediaPlayer自下定义了一个播放器。下面简单分享下心得:

1.明确需求

1)可以播放、暂停、快进、快退
2)快进、快退有2种方式,一种按钮点击,一种拖动条拖动。
3)播放音频时显示音频动画
4)播放完毕可选择是否显示重播按钮
5)播放时,视频不会有变形或者模糊。
6)当加载网络视频时
播放器有2种形式:

1.工具栏始终固定于显示区下面

上面的图例就是这种情况,这种情况一般用在裁剪视频时,为了防止工具栏遮挡显示区域。

2.工具栏浮于显示区上面

2.代码设计

模型构建

由上面的效果图,可以将自定义View划分成3个部分:播放显示区、工具栏、状态区。

上代码

下面我只说一下关键代码,其余的可以看源码。
1)定义自定义属性

  <declare-styleable name="CZVideoView">
        <attr name="sfvWidth"  format="dimension" >
            <enum name="fill_parent" value="-1" />
            <!-- The view should be as big as its parent (minus padding).
                 Introduced in API Level 8. -->
            <enum name="match_parent" value="-1" />
            <!-- The view should be only big enough to enclose its content (plus padding). -->
            <enum name="wrap_content" value="-2" />
        </attr>
        <attr name="sfvHeight"  format="dimension" >
            <enum name="fill_parent" value="-1" />
            <!-- The view should be as big as its parent (minus padding).
                 Introduced in API Level 8. -->
            <enum name="match_parent" value="-1" />
            <!-- The view should be only big enough to enclose its content (plus padding). -->
            <enum name="wrap_content" value="-2" />
        </attr>
        <attr name="toolMenuPosition">
            <enum name="on" value="1" />        <!--表示ToolMenu在SufaceView的Z轴上方。-->
            <enum name="below" value="2" />     <!--表示ToolMenu在SufaceView的下方。-->
        </attr>
    </declare-styleable>

2)初始化布局
根据自定义属性toolMenuPosition来加载不同形式的布局

     if(PlayMenuController.TOOL_MENU_POSITION_ON == toolMenuPosition){
            /**
             * 注意{@link R.layout.cz_video_view_position_on}中的{@link surfaceView}的layout_width属性,在xml里,要定义为wrap_content,
             * 如果定义成match_parent,会导致后面的resize失败。我也不知道原理是什么。TODO
             */
            LayoutInflater.from(context).inflate(R.layout.cz_video_view_position_on, this, true);
        }else if(PlayMenuController.TOOL_MENU_POSITION_BELOW == toolMenuPosition){
            /**
             * 注意{@link R.layout.cz_video_view_position_below}中的{@link surfaceView}的layout_width属性,在xml里,要定义为wrap_content,
             * 如果定义成match_parent,会导致后面的resize失败。我也不知道原理是什么。TODO
             */
            LayoutInflater.from(context).inflate(R.layout.cz_video_view_position_below, this, true);
            playMenuController.setAutoHidePlayMenu(false);
        }

动态创建状态区内部类StateView,和视频播放叠加。
3)视频大小适配
为防止视频变形,需要对surfaceView的大小进行适配。适配方案如下:
<1>获取当前surfaceView的宽高
<2>指定surfaceView新的宽高就是当前的宽高
<3>比较视频的宽度与高度
比较surfaceView的高度与视频的高度
如果surfaceView的高度 > 视频的高度,使surfaceView的高度等于视频的高度。(这样就保证视频虽然很小,但是不会被拉伸导致模糊。)

 int sfvMeasuredHeight = surfaceView.getMeasuredHeight();
            int sfvMeasuredWidth = surfaceView.getMeasuredWidth();
            int sfvNewWidth = sfvMeasuredWidth,sfvNewHeight = sfvMeasuredHeight;
            if(localSrc.getMediaType() == MediaDetailBean.MEDIA_TYPE_VIDEO){    //视频就要适配变形
                //sfv比视频还高,sfv与视频同高
                if(sfvMeasuredHeight > localSrc.getHeight()){
                    sfvNewHeight = localSrc.getHeight();
                }

                if(localSrc.getWidth() <= localSrc.getHeight()){
                    sfvNewWidth = (int) (1.0 * sfvNewHeight * localSrc.getWidth() / localSrc.getHeight());
                }else{
                    sfvNewWidth = mWidth;
                    sfvNewHeight = (int) (1.0 * sfvNewWidth * localSrc.getHeight() / localSrc.getWidth());
                }
            }

            resizeSurfaceView(sfvNewWidth, sfvNewHeight);

# 源码:

如有疑惑或者好的建议,或者想纠正作者的博文,请联系如下
公众号:微信公众号搜索“修符道人”或者扫描下方二维码

微信号:XinYi1349308479
QQ邮箱:1349308479@qq.com


0 条评论

发表回复

您的电子邮箱地址不会被公开。