关闭

手把手教你炫酷慕课网视频启动导航的完美实现

标签: vedioView导航视频
3186人阅读 评论(7) 收藏 举报
分类:

看了慕课网的视频启动导航真心感觉不错,然后呢试着去做了个一模一样的效果,个人感觉效果还是不错的。
先来看效果:
这里写图片描述

这里写图片描述

这里写图片描述

整体感觉效果还是非常不错的吧。

实现思路

看上面那个GIF图,分析可知。首先是一个显示慕课网LOGO的Activity,然后跳转到了今天我们要讲的引导效果的Activity

  • 根据它滑动的效果,可猜测是由ViewPager实现的。
  • ViewPager中有三个播放着动画或者视频的Fragment。
  • 底部有标识滑动到哪一页的小圆点。
  • 当滑动到第三页时,出现登录、注册按钮。

实现的技术分析:

打开慕课网App的引导页面,以为是用gif图片做的,后来发现每个引导页面都是加载的一段视频。 既然我们知道每个页面都是视频的话,那么就很好做了有木有,既然是几个引导页我就想到了轮播图那就使用viewPager来实现是比较轻松的,每个视频用Fragment这样的话复用率比较高,所以就选择用FragmentPagerAdapter,然后播放视频呢本来想用Vitamio然后呢发现videoView来实现比较简单,所以果断使用,然后还加上登录注册和首页,这里为了简单直观直接使用webView加载的效果是不是特别的炫,如果是第一次也会去慕课网那样的提示页,是不是感觉非常棒。

Android三种播放视频的方式

在Android中,我们有三种方式来实现视频的播放:

1、使用其自带的播放器。指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型。

2、使用VideoView来播放。在布局文件中使用VideoView结合MediaController来实现对其控制。

3、使用MediaPlayer类和SurfaceView来实现,这种方式很灵活。

videoView的使用

Android支持播放网络上的视频。在播放网络上的视频时,牵涉到视频流的传输,往往有两种协议,

一种是HTTP,一种是RTSP。这
两种协议最大的不同是,HTTP协议,不支持实时流媒体的播放,而RTSP协议就支持。
Android中自带的播放器,以及VideoView等都支持上述两种协议,因此,可以直接播放网络上的视频,唯一不同的就是URI。

VideoView播放视频的步骤:

1、在界面布局文件中定义VideoView组件,或在程序中创建VideoView组件
2、调用VideoView的如下两个方法来加载指定的视频
setVidePath(String path):加载path文件代表的视频
setVideoURI(Uri uri):加载uri所对应的视频
3、调用VideoView的start()、stop()、psuse()方法来控制视频的播放

VideoView使用注意:

1.先把要播放的视频放到res/raw目录下,注明我这里要播放的是Android项目中的资源文件,而不是访问SD卡播放视频。
2.视频格式必须是Android支持的格式(3gp,mp4,wmv),据说swf不支持,暂未试过。并且视频文件命名不能有大写字母,必须是小写字母、数字或下划线。
3.布局文件中添加VideoView组件
4.创建个String类型对象保存uri
5.调用VideoView的setVideoURI方法设置URI,参数为上面的uri
6.调用start()方法播放。

准备工作

1 .准备3个mp4格式的启动页视频
2.准备2个图片(白点)
3.准备几个webView需要加载的URL

代码解说

不多说看代码:
先来布局:(导航页)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:showIn="@layout/activity_main" tools:context=".MainActivity">
    <android.support.v4.view.ViewPager
        android:id="@+id/id_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
    <LinearLayout
        android:id="@+id/button_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="50dp"
        android:gravity="center_horizontal"
        android:orientation="horizontal"
        android:visibility="gone">

        <TextView
            android:id="@+id/login"
            android:layout_width="140dp"
            android:layout_height="48dp"
            android:background="@drawable/guide_login_btn_bg"
            android:gravity="center"
            android:text="登录/注册"
            android:textColor="@color/black_000000"
            android:textSize="18dp" />

        <TextView
            android:id="@+id/enter"
            android:layout_width="140dp"
            android:layout_height="48dp"
            android:layout_marginLeft="20dp"
            android:background="@drawable/guide_enter_btn_bg"
            android:gravity="center"
            android:text="立即体验"
            android:textColor="@color/white_66FFFFFF"
            android:textSize="18sp" />
    </LinearLayout>
    <LinearLayout
        android:id="@+id/dot_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp"
        android:orientation="horizontal" />
</RelativeLayout>

然后ViewPager里面使用的是Fragment里面使用的是VideoView来播放视频。所以自定义videoView便于视频的播放管理,看代码:

package com.richerpay.videoview.moocguide.view;

import android.annotation.TargetApi;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.VideoView;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class MCVideoView extends VideoView {
    public MCVideoView(Context context) {
        super(context,null);
    }
    public MCVideoView(Context context, AttributeSet attrs) {
        super(context, attrs,0);
    }
    public MCVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr, 0);
    }
    public MCVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
    }
    public void playVideo(Context context, Uri paramUri)
    {
        if (paramUri == null)
            throw new IllegalArgumentException("Uri can not be null");
        setVideoURI(paramUri);
        start();
        setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                mp.setLooping(true);
            }
        });
        setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                return true;
            }
        });
    }
}

其实不封装也是差不多的,代码很简单我们来看下Fragment的布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.richerpay.videoview.moocguide.view.MCVideoView
        android:id="@+id/videoview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <View
        android:id="@+id/guide_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

接下来我们来看Fragment里面的代码,也是很简单:

package com.richerpay.videoview.moocguide.fragmnet;

import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.richerpay.videoview.moocguide.R;
import com.richerpay.videoview.moocguide.view.MCVideoView;
public class GuideFragment extends Fragment {

    private View mBgView;
    private Context mContext;
    private MCVideoView mVideoView;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.mContext=context;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View localView = inflater.inflate(R.layout.guide_item_layout, null);
        initView(localView);
        return localView;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initData();
    }

    private void initView(View localView) {
        mVideoView = ((MCVideoView)localView.findViewById(R.id.videoview));
        mBgView = localView.findViewById(R.id.guide_bg);
    }

    private void initData() {
        Bundle localBundle = getArguments();
        int i = 0;
        int j = 0;
        int k = 0;
        if ((localBundle != null) && (localBundle.containsKey("index")))
            i = localBundle.getInt("index");
        try
        {
            String str = "guide_" + i;
            j = R.raw.class.getDeclaredField(str).getInt(this);
            int l = R.mipmap.class.getDeclaredField(str).getInt(this);
            k = l;
            if (j != 0)
                this.mVideoView.playVideo(mContext, Uri.parse("android.resource://" + this.mContext.getPackageName() + "/" + j));
            if (k != 0)
                this.mBgView.setBackgroundResource(k);
            return;
        }
        catch (Exception localException)
        {
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (this.mVideoView == null)
            return;
        this.mVideoView.stopPlayback();
    }
}

上面这段代码无非就是为了公用一个Fragment所以无非就是播放Raw文件下的不同视频而已。

好了我们来看下导航的代码:

package com.richerpay.videoview.moocguide;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.richerpay.videoview.moocguide.fragmnet.GuideFragment;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private ViewPager viewpager;
    private FragmentPagerAdapter mAdapter;
    private List<Fragment> mFragments;
    private ImageView[] images;
    private GuideFragment mTab01;
    private GuideFragment mTab02;
    private GuideFragment mTab03;
    private TextView login, enter;
    private LinearLayout button_layout, dot_layout;
    private ObjectAnimator mAnim;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //   requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        initView();

        setSelect(0);
        initDot(0);
    }

    private void initEvent() {
        login.setOnClickListener(this);
        enter.setOnClickListener(this);
    }


    private void initView() {
        login = (TextView) findViewById(R.id.login);
        enter = (TextView) findViewById(R.id.enter);
        button_layout = (LinearLayout) findViewById(R.id.button_layout);
        dot_layout = (LinearLayout) findViewById(R.id.dot_layout);
        viewpager = (ViewPager) findViewById(R.id.id_viewpager);
        mFragments = new ArrayList<Fragment>();
        Bundle bundel = new Bundle();
        mTab01 = new GuideFragment();
        bundel.putInt("index", 1);
        mTab01.setArguments(bundel);
        mTab02 = new GuideFragment();
        Bundle bunde2 = new Bundle();
        bunde2.putInt("index", 2);
        mTab02.setArguments(bunde2);
        mTab03 = new GuideFragment();
        Bundle bunde3 = new Bundle();
        bunde3.putInt("index", 3);
        mTab03.setArguments(bunde3);
        mFragments.add(mTab01);
        mFragments.add(mTab02);
        mFragments.add(mTab03);

        mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {

            @Override
            public int getCount() {
                // TODO Auto-generated method stub
                return mFragments.size();
            }

            @Override
            public Fragment getItem(int arg0) {
                // TODO Auto-generated method stub
                return mFragments.get(arg0);
            }
        };

        viewpager.setAdapter(mAdapter);

        viewpager.setOnPageChangeListener(new android.support.v4.view.ViewPager.OnPageChangeListener() {

            @Override
            public void onPageSelected(int pos) {
                int currentItem = viewpager.getCurrentItem();
                setTab(currentItem);
                initDot(pos);
                images[pos].setEnabled(true);
            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {


            }

            @Override
            public void onPageScrollStateChanged(int arg0) {


            }
        });
    }
    private void setSelect(int i) {
        setTab(i);
        viewpager.setCurrentItem(i);
    }
    private void setTab(int i) {
        switch (i) {
            case 0:
                button_layout.setVisibility(View.GONE);
                fadeInAnim(button_layout);
                break;
            case 1:
                button_layout.setVisibility(View.GONE);
                fadeInAnim(button_layout);
                break;
            case 2:
                button_layout.setVisibility(View.VISIBLE);
                initEvent();
                break;
            default:
                break;
        }
    }
    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.login) {
            goLoginActivity();
        }
        if (v.getId() == R.id.enter) {
            if (Constant.isFrist)
                goIndexActivity();
            else
                goInitActivity();
        }
    }
    private void goInitActivity() {
        startActivity(new Intent(this, InitActivity.class));
        finish();
    }
    private void goIndexActivity() {
        startActivity(new Intent(this, IndexActivity.class));
        finish();
    }

    private void goLoginActivity() {
        startActivity(new Intent(this, LoginActivity.class));
        finish();
    }

    private void fadeInAnim(View paramView) {
        if (Build.VERSION.SDK_INT < 11)
            return;
        float[] arrayOfFloat = new float[2];
        arrayOfFloat[0] = 0.0F;
        arrayOfFloat[1] = 1.0F;
        mAnim = ObjectAnimator.ofFloat(paramView, "alpha", arrayOfFloat).setDuration(1000L);
        AnimatorSet localAnimatorSet = new AnimatorSet();
        localAnimatorSet.play(mAnim);
        localAnimatorSet.start();
    }
    /**
    *初始化下面的点
    */
    private void initDot(int select) {
        //设置点的个数为fragment的数量
        images = new ImageView[mFragments.size()];
        //先移除所有的点
        dot_layout.removeAllViews();
        for (int i = 0; i < mFragments.size(); i++) {
            ImageView localImageView = new ImageView(this);
            LinearLayout.LayoutParams localLayoutParams = new LinearLayout.LayoutParams(-2, -2);
            //左边距为30
            localLayoutParams.leftMargin = 30;
            localImageView.setLayoutParams(localLayoutParams);
            localImageView.setImageResource(R.drawable.dot_bg);
            if (i == select)  //如果选中则图片变为白点
                localImageView.setEnabled(true);
            else    //否者就为暗一点的白点
                localImageView.setEnabled(false);
            images[i] = localImageView;
            dot_layout.addView(localImageView);
        }
    }
}

上面这代码无非就是把fragment适配到viewPager里面,并且根据选择到第几页来控制下面的白点,当到第三页时让登录注册按钮显示,和点击按钮执行相关的操作。

为了让效果更加好点,点击登录注册用的webView加载,顺便对webView进行了简单的封装。

 package com.richerpay.videoview.moocguide.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.view.KeyEvent;
import android.webkit.WebSettings;
import android.webkit.WebSettings.RenderPriority;
import android.webkit.WebSettings.ZoomDensity;
import android.webkit.WebView;
import android.webkit.WebViewClient;
/**
 * 自定义WebView,长按图片获取图片url
 *
 */
public class CustomWebView extends WebView{
    private Context context;

    public CustomWebView(Context context) {
        super(context);
        this.context = context;
        initSettings();
    }

    private void initSettings() {
        // 初始化设置
        WebSettings mSettings = this.getSettings();
        mSettings.setJavaScriptEnabled(true);//开启javascript
        mSettings.setDomStorageEnabled(true);//开启DOM
        mSettings.setDefaultTextEncodingName("utf-8");//设置字符编码
        //设置web页面
        mSettings.setAllowFileAccess(true);//设置支持文件流
        mSettings.setSupportZoom(true);// 支持缩放
        mSettings.setBuiltInZoomControls(true);// 支持缩放
        mSettings.setUseWideViewPort(true);// 调整到适合webview大小
        mSettings.setLoadWithOverviewMode(true);// 调整到适合webview大小
        mSettings.setDefaultZoom(ZoomDensity.FAR);// 屏幕自适应网页,如果没有这个,在低分辨率的手机上显示可能会异常
        mSettings.setRenderPriority(RenderPriority.HIGH);
        //提高网页加载速度,暂时阻塞图片加载,然后网页加载好了,在进行加载图片
        mSettings.setBlockNetworkImage(true);
        mSettings.setAppCacheEnabled(true);//开启缓存机制

        setWebViewClient(new MyWebViewClient());

    }

    private class MyWebViewClient extends WebViewClient {
        /**
         * 加载过程中 拦截加载的地址url
         * @param view
         * @param url  被拦截的url
         * @return
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            return super.shouldOverrideUrlLoading(view, url);
        }
        /**
         * 页面加载过程中,加载资源回调的方法
         * @param view
         * @param url
         */
        @Override
        public void onLoadResource(WebView view, String url) {
            super.onLoadResource(view, url);
        }
        /**
         * 页面加载完成回调的方法
         * @param view
         * @param url
         */
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            // 关闭图片加载阻塞
            view.getSettings().setBlockNetworkImage(false);
        }
        /**
         * 页面开始加载调用的方法
         * @param view
         * @param url
         * @param favicon
         */
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }
        @Override
        public void onReceivedError(WebView view, int errorCode,
                                    String description, String failingUrl) {
            super.onReceivedError(view, errorCode, description, failingUrl);
        }
        @Override
        public void onScaleChanged(WebView view, float oldScale, float newScale) {
            super.onScaleChanged(view, oldScale, newScale);
            CustomWebView.this.requestFocus();
            CustomWebView.this.requestFocusFromTouch();
        }
    }
    @Override
    // 设置回退
    // 覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && this.canGoBack()) {
            this.goBack(); // goBack()表示返回WebView的上一页面
            return true;
        }
        return super.onKeyDown(keyCode,event);
    }
}

结尾

本来这篇是昨天就发布了的,结果不知道怎么就删除了,好伤心,重新整理再发一下。想要完整代码的请移步github欢迎大家star or fork,你也可以去csdn那去下载MoocGuide.zip,觉得还不错就顶下,还有待提高多给点建议。

come on ,enjoy it.

5
0
查看评论

《手把手教你读财报》- 读书总结

本书的特色 以贵州茅台2013年财报为线索,引领全书,读起来不至于太枯燥。 理论+实践,很好的典范! 贵州茅台,业务比较单一,财报比较好理解。
  • FansUnion
  • FansUnion
  • 2016-08-10 17:17
  • 2507

手把手教你架构3D游戏引擎

在这里将多年游戏研发经验的积累写成一本书奉献给读者,目前已经开始预售,网址: http://www.broadview.com.cn/article/70 该书主要是将游戏中经常使用的技术给大家做了一个总结,书中的代码可以直接应用到项目开发中。
  • jxw167
  • jxw167
  • 2016-12-08 10:16
  • 5265

手把手教你安卓入门(二)

我们就开始正式开发“计算器”应用
  • anddlecn
  • anddlecn
  • 2016-05-23 20:59
  • 9719

手把手教你学Ztree

https://note.wiz.cn/pages/manage/biz/payRead.html?kb=3fe9d146-6498-4882-b75c-f533442aba5b
  • huaweitman
  • huaweitman
  • 2017-06-21 17:51
  • 684

手把手教你实现SVM算法(二)

一.SMO算法的原理 SMO算法和以往的一些SVM改进算法一样,是把整个二次规划问题分解为很多较易处理的小问题,所不同的是,只有SMO算法把问题分解到可能达到的最小规模:每次优化只处理两个样本的优化问题,并且用解析的方法进行处理。我们将会看到,这种与众不同的方法带来了一系列不可比拟的优势。 对S...
  • alvine008
  • alvine008
  • 2013-06-14 18:09
  • 12256

CSS3实现酷炫导航

上面是一个效果图,代码在下面: html<html> <head> <meta charset="utf-8"/> <title>CSS3 实现的导航</title> <link type...
  • u011043843
  • u011043843
  • 2015-05-05 12:14
  • 1428

《手把手教你学C语言》学习笔记(1)---C语言的特点

C语言的两个知识点库和指针
  • guochaoxxl
  • guochaoxxl
  • 2017-04-22 08:18
  • 724

GDB(二):启动GDB

GDB启动格式..
  • lincoln_2012
  • lincoln_2012
  • 2016-10-20 00:36
  • 205

手把手教你如何建立自己的Linux系统

http://cross-lfs.org/view/clfs-embedded/arm/ http://blog.chinaunix.net/uid-436750-id-2123580.html http://www.ha97.com/book/lfs-book-6.6/pr...
  • soso90soso
  • soso90soso
  • 2014-05-06 19:47
  • 339

推荐!手把手教你使用Git的详细操作

原文出处:涂根华的博客–推荐!手把手教你使用Git的详细操作 以下是其中的一部分,想了解更多,请参考涂根华的博客 Git基本常用命令: mkdir: XX (创建一个空目录 XX指目录名)pwd: 显示当前目录的路径。git init 把当前的目录变成可以管理的git仓库,生成隐藏.git文件...
  • xsj_blog
  • xsj_blog
  • 2016-06-16 10:54
  • 584
    个人资料
    • 访问:469809次
    • 积分:5518
    • 等级:
    • 排名:第5752名
    • 原创:97篇
    • 转载:20篇
    • 译文:1篇
    • 评论:274条
    博客专栏
    文章分类
    sina 微博
    最新评论