原创安卓手机QQ7.0登录界面动态背景视频实现方案

qq7.0登录界面动态背景实现 qq7.0登录界面动态视频背景实现 android动态视频背景 android动态背景

分析qq7.0:

视频在打开登录界面就开始播放 了,而且期间无黑屏
而且是循环播放的

画质问题这里就不说了,这个看视频源了。

可以让不规则的宽高各种宽高不定的视频比例 以及视频大小都能 适应任意安卓手机的宽高 包括平板,且不留任何缝隙

播放器控件选取:解决的是手机适配的问题,另外是播放器控件,这里选择系统播放器比较好. 因为有些播放器不支持读取asset文件夹的Uri比如七牛的

视频加载速度比较慢第一帧用图片代替且需要耦合视频的第一帧

图片的第一帧截取我用的是一个比较专业的adobe premiere的开发工具 这个你们也可以让ps等后期的去做,这种事情对我来说的话还是小kiss,

技术点:
如何读取资源文件视频
如何测量
如何根据视频大小计算应该缩放的比例大小 解决任意尺寸视频手机不留黑边
如何让图片的封面缩放大小和视频的缩放大小吻合
如何调用onStart短暂黑屏问题

架构搭建

资源的读取


   String VIDEO_PATH = "android.resource://" + BuildConfig.APPLICATION_ID + "/" + R.raw.login;
videoView.setVideoURI(Uri.parse(Constants.VIDEO_PATH));

创建一个自定义视频类 自定义图片类 图片在视频的上面因为视频不是马上播放 加载有一定时间这里也会存在一个黑屏

关于读取视频的问题,之前尝试过读取assests里面的视频失败了,在stackoverflow照的方案也不行,最后还是把视频放到和res/raw文件夹里面了,

具体实现之视频控件

1. 拿到视频的宽高度才能进行测量重新布局

在继承的VideoView里添加setOnPreparedListener方法获取视频宽高度设置给成员变量就可以拿到了

 super.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(final MediaPlayer mp) {


      SystemVideoView.this.videoWidth = mp.getVideoWidth();
      SystemVideoView.this.videoHeight = mp.getVideoHeight();

}
}

2. 继承VideoView重写onMeasure测量方法

需要一个完美的算法来解决宽高都铺满屏幕问题

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        MeasureUtil.Size measure = MeasureUtil.measure(displayAspectRatio, widthMeasureSpec, heightMeasureSpec, videoWidth, videoHeight);

        setMeasuredDimension(measure.width, measure.height);
    }

这里的算法比较麻烦,不懂的同学搬用模版代码
测量工具类MeasureUtil.measure方法抽出来
的大致代码是

    public static MeasureUtil.Size measure(int displayAspectRatio, int widthMeasureSpec, int heightMeasureSpec, int videoWidth, int videoHeight) {


 if (widthMode == View.MeasureSpec.EXACTLY && heightMode == View.MeasureSpec.EXACTLY) {  

  if (percentVideo > percentView) {
                            width = widthSize;
                            height = (int) ((float) widthSize / percentVideo);
                        } else {
                            height = heightSize;
                            width = (int) ((float) heightSize * percentVideo);
                        }

    }else if (widthMode == View.MeasureSpec.EXACTLY) {
                width = widthSize;
                height = widthSize * videoHeight / videoWidth;
                if (heightMode == View.MeasureSpec.AT_MOST && height > heightSize) {
                    height = heightSize;
                }
            } else if (heightMode == View.MeasureSpec.EXACTLY) {
                height = heightSize;
                width = heightSize * videoWidth / videoHeight;
                if (widthMode == View.MeasureSpec.AT_MOST && width > widthSize) {
                    width = widthSize;
                }
            } else {
                width = videoWidth;
                height = videoHeight;
                if (heightMode == View.MeasureSpec.AT_MOST && videoHeight > heightSize) {
                    height = heightSize;
                    width = heightSize * videoWidth / videoHeight;
                }

                if (widthMode == View.MeasureSpec.AT_MOST && width > widthSize) {
                    width = widthSize;
                    height = widthSize * videoHeight / videoWidth;
                }
            }

}


public static class Size {
        public final int width;
        public final int height;

        public Size(int width, int height) {
            this.width = width;
            this.height = height;
        }
    }

3. 黑屏问题解决探讨

只要调用start就会有一定概率的黑屏毫秒
先不管测量铺满问题,我们发现会存在一个坑,就是视频黑屏问题,进入这个界面肯定要让它不黑屏的.
1.尝试过在onPrepared里面再在让VideoView显示隐藏结果没卵用
1.直接隐藏控件在方案1的基础上延长几秒,start过程中依然隐藏(不同手机需要的延长时间不同,)但是如果0秒到1秒的过程中如果没有画面动还好,如果动了,延长超过1秒后在显示此控件那么视频就需要留长 不然首帧和此时videoview显示的时间不一致,后面发现这种死办法又没法解决循环播放问题

最后的解决方法通过百度找到 是根据info的视频第一帧来判断:

  mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                    @Override
                    public boolean onInfo(MediaPlayer mp, int what, int extra) {
                        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
                            if (onCorveHideListener != null) {
                                onCorveHideListener.requestHide();
                            }
                        }
                        if (onInfoListener != null) {
                            onInfoListener.onInfo(mp, what, extra);
                        }
                        return false;
                    }
                });

图片的解决方案和视频一样,你这都需要代码得话打赏一个吧,哈哈,

隐藏的方法在外面了。叫 setOnCorveHideListener ,实际上进入界面就应该马上显示画面的隐藏视频的话是一个白屏,所以这里需要

最后界面activity或者fragment代码

    String VIDEO_PATH = "android.resource://" + BuildConfig.APPLICATION_ID + "/" + R.raw.login;

    loginActivityBinding.videoView.setDisplayAspectRatio(MeasureUtil.ASPECT_RATIO_PAVED_PARENT);
        loginActivityBinding.videoView.setOnCorveHideListener(new SystemVideoView.OnCorveHideListener() {
            @Override
            public void requestHide() {
                loginActivityBinding.corver.setVisibility(View.GONE);
            }
        });
        loginActivityBinding.videoView.setVideoURI(Uri.parse(Constants.VIDEO_PATH));
        loginActivityBinding.videoView.start();
        loginActivityBinding.videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                loginActivityBinding.videoView.seekTo(0);
                loginActivityBinding.videoView.start();
            }
        });




 @Override
    public void onPause() {
        super.onPause();
        loginActivityBinding.videoView.pause();
    }

    @Override
    public void onResume() {
        super.onResume();
        loginActivityBinding.videoView.start();
    }

完整SystemVideoView代码

public class SystemVideoView extends VideoView {


    private int videoWidth;//width
    private int videoHeight;
    private int displayAspectRatio;

    public SystemVideoView(Context context) {
        super(context);
    }

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

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

    }

    protected void init(Context context) {
        this.videoHeight = context.getResources().getDisplayMetrics().heightPixels;
        this.videoWidth = context.getResources().getDisplayMetrics().widthPixels;

        super.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(final MediaPlayer mp) {

                SystemVideoView.this.videoWidth = mp.getVideoWidth();
                SystemVideoView.this.videoHeight = mp.getVideoHeight();
                mp.setOnInfoListener(new MediaPlayer.OnInfoListener() {
                    @Override
                    public boolean onInfo(MediaPlayer mp, int what, int extra) {
                        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
                            if (onCorveHideListener != null) {
                                onCorveHideListener.requestHide();
                            }
                        }
                        if (onInfoListener != null) {
                            onInfoListener.onInfo(mp, what, extra);
                        }
                        return false;
                    }
                });
            }
        });
    }

    MediaPlayer.OnPreparedListener onPreparedListener = null;

    public interface OnCorveHideListener {
        void requestHide();
    }

    @Override
    public void setOnInfoListener(MediaPlayer.OnInfoListener onInfoListener) {
        this.onInfoListener = onInfoListener;
    }

    MediaPlayer.OnInfoListener onInfoListener;

    public void setOnCorveHideListener(OnCorveHideListener onCorveHideListener) {
        this.onCorveHideListener = onCorveHideListener;
    }

    OnCorveHideListener onCorveHideListener;

    @Override
    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
        this.onPreparedListener = l;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);


        MeasureUtil.Size measure = MeasureUtil.measure(displayAspectRatio, widthMeasureSpec, heightMeasureSpec, videoWidth, videoHeight);
        setMeasuredDimension(measure.width, measure.height);





    public void setDisplayAspectRatio(int var1) {
        displayAspectRatio = var1;
        this.requestLayout();

    }


    @Override
    public boolean isPlaying() {
        return false;
    }

    public int getDisplayAspectRatio() {
        return displayAspectRatio;
    }

    public void setCorver(int resource) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), resource, opts);

    }

我的博客
我的简书

发布了31 篇原创文章 · 获赞 24 · 访问量 12万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览