VR小项目(三)

VR小项目(三)



17.打开上面上面创建好的VrVideoFragment并继承我们自己写的BaseFragment并实现他的两个方法
/**
 * Date:2017/3/18
 * author:陈箫阳ChenXiaoYang
 * furction:
 */

public class VrVideoFragment extends BaseFragment {
    private RecyclerView recyclerView;

    @Override
    public RecyclerView.LayoutManager getLayoutManager() {
        //VR视频使用GridView的样式,参数    1.上下文      2.决定一行几列
        return new GridLayoutManager(getActivity(), 2);
    }

    //在这里我们要复写onViewCreated方法
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
        //从接口中拿到LayoutManager
        RecyclerView.LayoutManager loaderManager = getLayoutManager();
        //设置LayoutManager,让子类不用再设置
        recyclerView.setLayoutManager(loaderManager);
        //使用开源框架OKGO,加载网址
        OkGo.get(ApiUrls.URL_Query)
    }

    @Override
    protected RecyclerView.Adapter getAdapter() {
        return null;
    }
}
在这里ApiUrls会报红,我们需要使用快捷键创建ApiUrls类用于存放网络数据,然后将Apiurls放入utli包中
/**
 * Date:2017/3/19
 * author:陈箫阳ChenXiaoYang
 * furction:
 */
public class ApiUrls {
    public static String API_HOST = "api.youkes.com";
    public static int API_PORT = 8081;
    public static String URL_Query = "http://" + API_HOST + ":" + API_PORT + "/api/video/query";
}
此时回到VrVideoFragment类 
在这里我们要使用JSON需要导入:com.alibaba:fastjson:1.2.29
步骤:按住control+alt+shift+s会弹出一个Project Structure点击所要添加的项目,点击Dependencies,点击+号,选择Library Dependency

.cacheKey(ApiUrls.URL_Query)//默认加载键
.cacheMode(CacheMode.DEFAULT)//采用默认格式
.execute(new StringCallback() {
    //网络请求成功的回调
    @Override
    public void onSuccess(String s, Call call, Response response) {
        try {
            //创建原生的JSONObject来解析数据
            JSONObject obj = new JSONObject(s);
            String content = obj.getString("content");
            //然后报解析的数据先放在Bean类,再放到集合里,这里我们用Gson,fastJson会更方便
            List<VideoItem> videoItems = JSON.parseArray(content, VideoItem.class);
            //给RecyclerView设置适配器,把数据集合传到适配器里
            recyclerView.setAdapter(new VrVideoAdapter(videoItems));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
});
在这里List集合的VideoItem会报红,使用快捷键创建VideoItem类, VrVideoAdapter也会报红,使用快捷键创建VrVideoAdapter适配器类实现一个内部抽象方法然后在让他调用父类的方法
/**
 * Date:2017/3/19
 * author:陈箫阳ChenXiaoYang
 * furction:
 */
public class VideoItem {
    public String vtype;
    public String id;
    public String key;
    public String play;
    public String title;
    public String img;
    public String url;
    public String isbin;
    public String t0;
    public String t1;
    public String t2;
    public String userName;
    public String userNick;
    public String userPhoto;
    public String vclass;
    public int width;
    public int height;
    public float score0;
    public long date;
    public String _id;
    public String userId;
    public String[] tags;
    public int cnt;
    public String type;
    public String videoChannelName;
    public String videoChannelId;
    public String text;
    public String textSimple;
    public String dateCnSimple;
}

/**
 * Date:2017/3/17
 * author:陈箫阳ChenXiaoYang
 * furction:VR视频模块RecyclerView所需适配器
 */
public class VrVideoAdapter extends BaseQuickAdapter<VideoItem> {
    //通过构造方法,加载一个默认布局及获取传过来的数据
    public VrVideoAdapter(List<VideoItem> videoItems) {
        super(R.layout.vr_video_list_item, videoItems);
    }

    @Override
    protected void convert(BaseViewHolder helper, VideoItem item) {
    }
}
在这里R.layout.vr_video_list_item会报红,使用快捷键创建vr_video_list_item布局文件,显示一些简单的布局,用到了一些颜色需要以下步骤
    1.打开res下的values包再打开colors布局文件添加一些颜色
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <!--vr_video_list_item里自定义的颜色-->
    <color name="white_light">#f2f2f2</color>
    <color name="white">#fafafa</color>
    <color name="gray_dark_blue">#5A6377</color>
    <color name="gray_light">#efefef</color>
    <color name="black">#ff000000</color>
    <color name="gray_less_light">#666666</color>
    <color name="gray">#777</color>
    <color name="gray_dark">#383838</color>
    <color name="green_light">#8e9ea4</color>
    <color name="green">#34515c</color>
    <color name="green_dark">#1e3e4a</color>
    <color name="night_mask">#90000000</color>
    <color name="gray_darker">#2b2b2b</color>
    <color name="gray_lighter">#efefef</color>
    <color name="gray_alpha_light">#90999999</color>
    <color name="semitransparent_light">#20000000</color>
    <color name="white_dark">#f3f3f3</color>
</resources>
    2.在drawable下创建select_button.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
          android:drawable="@color/white_light"></item>
    <item android:drawable="@color/white"></item>
</selector>
回到VrVideoAdapter适配器类,
注意:这里特别要注意的是SimpleDateFormat

com.ibm.icu.text.SimpleDateFormatjava.text.SimpleDateFormat比较

  1.fomat()方法,前者比后者大一小时

  2.parse()方法,前者比后者小一小时

  3.当然 java.text.SimpleDateFormat得到的结果是正确的

com.ibm.icu.text.SimpleDateFormat是ICU4J中的一个类。ICU4J 是IBM的国际化开发组件ICU 的Java语言实现版本。为何会发生这种怪异现象,我也没搞清楚,初步猜测是因为ibm这个包的默认时区不同。所以大家用ICU这个SimpleDateFormat时应该注意导入是哪个包


//标签TextView的控件Id
private int[] ids = {R.id.tag0, R.id.tag1, R.id.tag2};

@Override
protected void convert(BaseViewHolder helper, VideoItem item) {
    //设置Item的标题,从bean类里拿对象的数据,直接就可以根据控件ID设置进去,这是开源框架的便利
    helper.setText(R.id.topic_init_title, item.title);
    //设置Item的时间,使用simpleDateFormat(java的知识点),对时间数据进行格式化
    helper.setText(R.id.date_text, new SimpleDateFormat("MM/DD/yyyy").format(item.date));
    //根据控件ID获取到控件对象
    ImageView topicImg = helper.getView(R.id.topic_init_img);
    //使用开源框架,根据网址加载图片
    Glide.with(helper.getConvertView().getContext())//获取上下文
            .load(item.img)//网址
            .into(topicImg);//ImageView控件对象
    //从bean类里拿到标签
    String[] tags = item.tags;
    //根据标签的数量,做对应的循环操作,把标签设置到TextView文本里
    for (int x = 0; x < tags.length; x++) {
        //设置文本,参数  1 数组里的ID   2 要塞入的数据
        helper.setText(ids[x], tags[x]);
    }
}
到此VR视屏的页面就制作好了
效果图

18. 接下来就要编写VR视屏的点击事件了
首先在convert方法中获取item并设置点击事件
//B.获取到item容器的ID值,设置点击事件
View view = helper.getView(R.id.video_layout);
//使用设置标签的形式,以控件为容器,把数据放入其中,进行传递
view.setTag(item);
//设置点击事件
view.setOnClickListener(listener);
在这里listener会报红,这时我们需要在convert方法外创建私有的listener点击事件
//B.点击事件的处理
private View.OnClickListener listener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //从控件里取出数据,进行强类型转换
        VideoItem item = (VideoItem) v.getTag();
        //创建Intent对象, 参数  1.上下文   2.类字节,显示播放详情类
        Intent intent = new Intent(v.getContext(), VideoDeTailActivity.class);
        //需要传递的数据,把数据放入Intent,进行传输
        intent.putExtra("title", item.title);
        intent.putExtra("img", item.img);
        intent.putExtra("text", item.text);
        intent.putExtra("play", item.play);
        //获取上下文,开启Activity的跳转
        v.getContext().startActivity(intent);
    }
};

19.在这里VideoDeTailActivity类会报红,因为还没有这个跳转的类,所以我们要使用快捷键创建VideoDeTailActivity类并创建activity_video_de_tail布局文件
首先编写布局文件

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:id="@+id/video_detail"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:background="@color/white">
    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical">
            <LinearLayout
                android:id="@+id/control_bar"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="horizontal"
                android:padding="2dip">
                <TextView
                    android:id="@+id/title_text"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_margin="8dip"
                    android:text=""
                    android:textSize="16sp"/>
            </LinearLayout>
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_margin="4dp"
                android:background="@color/gray_lighter"
                android:orientation="horizontal">
                <ImageView
                    android:id="@+id/detail_img_view"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:background="@color/black"
                    android:clickable="true"
                    android:scaleType="centerCrop"
                    android:src="@mipmap/pictures_no"/>
                <TextView
                    android:id="@+id/video_type"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@color/semitransparent_light"
                    android:padding="8dp"
                    android:text="视频"
                    android:textColor="@color/white"
                    android:textStyle="bold"/>
                <ImageButton
                    android:id="@+id/play_link"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"

                    android:layout_centerHorizontal="true"
                    android:layout_centerVertical="true"

                    android:background="#22222222"
                    android:contentDescription="播放语音"
                    android:gravity="center"
                    android:src="@drawable/mediacontroller_play_button"/>
            </RelativeLayout>
            <TextView
                android:id="@+id/detail_text"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_margin="8dip"
                android:textColor="@color/gray_less_light"
                android:textSize="16sp"/>
        </LinearLayout>
    </ScrollView>
</FrameLayout>
在这里mediacontroller_play_button会报红,使用快捷键创建布局文件,在这里有一些图片
在drawable下创建mediacontroller_play_button.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@mipmap/mediacontroller_play02"/>
    <item android:drawable="@mipmap/mediacontroller_play01"/>
</selector>
20.回到VideoDeTailActivity类,接收跳转数据
public class VideoDeTailActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_de_tail);
        init();
    }
    //初始化数据
    private void init() {
        //拿到传过来的Intent对象
        final Intent intent = getIntent();
        //从Intent对象里,根据键值,拿到我们所需要的数据
        String title = intent.getStringExtra("title");
        String img = intent.getStringExtra("img");
        String text = intent.getStringExtra("text");
        final String play = intent.getStringExtra("play");
        //方别把拿到的数据放入对应的控件里,设置标题
        TextView mTextView = (TextView) findViewById(R.id.title_text);
        mTextView.setText(title);
        //用Glide设置图片
        ImageView ivImg = (ImageView) findViewById(R.id.detail_img_view);
        Glide.with(this)//上下文
                .load(img)//UI地址
                .into(ivImg);//ImageView控件对象
        //设置影片介绍文本
        TextView tv_detail = (TextView) findViewById(R.id.detail_text);
        tv_detail.setText(text);
        //找到ImageButton控件对象,设置点击事件
        findViewById(R.id.play_link).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent vrIntent = new Intent(VideoDeTailActivity.this, VideoPlayerActivity.class);
                //使用Intent传输所要传的值
                vrIntent.putExtra("play", play);
                //开启界面
                startActivity(vrIntent);
            }
        });
    }
}
在这里VideoPlayerActivity会报红因为没有这个跳转类,所以创建VideoPlayerActivity类并创建activity_video_player.xml布局文件
首先编写activity_video_player.xml  

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.google.vr.sdk.widgets.video.VrVideoView
        android:id="@+id/vr_video"
        android:layout_width="match_parent"
        android:layout_height="250dp"/>

    <android.support.v7.widget.AppCompatSeekBar
        android:id="@+id/seek_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
    />

    <TextView
        android:id="@+id/tv_progress"
        android:textSize="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>
VR视屏要导入VR资源包
打开gvr-android-sdk-master打开libraries

在Studio中导入
步骤:点击File<New<Improp module粘贴文件路径点击Finish

然后按住control+alt+shift+s会弹出一个Project Structure点击所要添加的项目,点击Dependencies,点击+号,选择Module Dependency

最后回到VideoPlayerActivity类获取跳转内容,并编写VR视屏界面
public class VideoPlayerActivity extends AppCompatActivity {
    private VrVideoView vr_video;
    private SeekBar seek_bar;
    private TextView tv_progress;
    private VideoLoadTask mVideoLoadTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_player);
        //获取传过来的Intent
        Intent intent = getIntent();
        //从Intent里拿到我们的数据
        String play = intent.getStringExtra("play");
        //A.进行控件的初始化
        vr_video = (VrVideoView) findViewById(R.id.vr_video);
        seek_bar = (SeekBar) findViewById(R.id.seek_bar);
        tv_progress = (TextView) findViewById(R.id.tv_progress);
        //隐藏VR效果左下角的信息按钮显示
        vr_video.setInfoButtonEnabled(false);
        //切换VR的模式   参数:VrVideoView.DisplayMode.FULLSCREEN_STEREO:设备模式(手机横着放试试)VrVideoView.DisplayMode..FULLSCREEN_MONO手机模式
        vr_video.setDisplayMode(VrVideoView.DisplayMode.FULLSCREEN_STEREO);
        //D.对VR视频进行事件监听
        vr_video.setEventListener(new MyEventListener());
        //B.播放VR效果,只需执行异步任务即可
        mVideoLoadTask = new VideoLoadTask();
        mVideoLoadTask.execute(play);
    }

    //B.由于VR资源数据量大,获取需要时间,故把加载视频放到子线程中进行,主线程来显示,可以使用一个异步线程AsyncTask或EventBus技术完成.
    //B.自定义一个类继承AsyncTask,只使用我们需要的方法.完成在子线程加载图片资源,在主线程显示
    private class VideoLoadTask extends AsyncTask<String, Void, Void> {
        //B.该方法在子线程运行,从本地文件中把资源加载到内存中
        @Override
        protected Void doInBackground(String... strings) {
            //创建VrVideoView.Options对象,决定VR是普通的效果,还是立体效果
            VrVideoView.Options options = new VrVideoView.Options();
            //立体模式
            options.inputType = VrVideoView.Options.TYPE_STEREO_OVER_UNDER;
            //处理加载的视频格式
            //FORMAT_DEFAULT:默认格式(SD卡或assets)
            //FORMAT_HLS:流媒体数据格式(直播)
            options.inputFormat = VrVideoView.Options.FORMAT_DEFAULT;
            try {
                //提示:视频加载的方法还做了把视频读取到内存中的操作,所以它有一个矛盾,调用该方法是放在主线程还是子线程(一般我们放在子线程)
                //使用VR控件对象,从资产目录加载视频数据,显示效果 参数: 1.String对象 2.VrVideoView.Options对象,决定显示效果
                //vr_video.loadVideoFromAsset(strings[0], options);//不要管他在爆红,就在子线程里执行
                //使用VR控件对象,从网络加载视频数据,显示效果(要加网络权限)   参数:   1.视频网址,String对象
                vr_video.loadVideo(Uri.parse(strings[0]), options);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    //C.因为VR很占用内存,所以当界面进入OnPause状态,暂停VR视图显示,进入OnResume状态,继续VR视图显示,进入OnDestroy状态,杀死VR,关闭异步任务
    //当失去焦点时,回到
    @Override
    protected void onPause() {
        super.onPause();
        //暂停渲染和显示
        vr_video.pauseRendering();
    }

    //当获取焦点时,回调
    @Override
    protected void onResume() {
        super.onResume();
        //继续渲染和显示
        vr_video.resumeRendering();
    }

    //当Activity销毁时,回调
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //关闭渲染视图,回调
        vr_video.shutdown();
        //在退出Activity时,如果异步任务没有取消,则取消
        if (mVideoLoadTask != null) {
            if (!mVideoLoadTask.isCancelled()) {
                mVideoLoadTask.cancel(true);
            }
        }
    }

    //VR运行状态监听类,自定义一个类继承VrVideoEventListener,复写里面需要的方法
    private class MyEventListener extends VrVideoEventListener {
        //当VR视图加载成功的时候的回调,此时还未开始播放
        @Override
        public void onLoadSuccess() {
            super.onLoadSuccess();
            //获取视频的长度
            long max = vr_video.getDuration();
            //设置seekbar的进度最大值
            seek_bar.setMax((int) max);
        }

        //当VR视图加载失败的时候回调的方法
        @Override
        public void onLoadError(String errorMessage) {
            super.onLoadError(errorMessage);
            Toast.makeText(VideoPlayerActivity.this, "播放失败", Toast.LENGTH_SHORT).show();
        }

        //当视频开始播放,每次进入下一帧的时候,回调这个方法(就是播放时,会不停的回调该方法)
        @Override
        public void onNewFrame() {
            super.onNewFrame();
            //获取当前视频的播放时间位置
            int currentPosition = (int) vr_video.getCurrentPosition();
            //设置seekBar的进度条
            seek_bar.setProgress(currentPosition);
            //显示播放的进度数字
            tv_progress.setText("播放进度:" + String.format("%.2f", currentPosition / 1000.f));

        }

        //当视频播放结束后的回调
        @Override
        public void onCompletion() {
            super.onCompletion();
            //让视频回到0点
            vr_video.seekTo(0);
            //视频停止
            vr_video.pauseVideo();
            //让进度条也设置到0点
            seek_bar.setProgress(0);
            //播放完成后,重新设置标签,标签true代表着视频处于暂停的状态.
            isPaused = false;
        }

        //设置一个视频播放状态的标签
        private boolean isPaused = true;

        //重写点击视图的方法,是视频被点击时,播放或者暂停
        @Override
        public void onClick() {
            super.onClick();
            //根据标签,判断当前视频的状态,做对应的逻辑处理
            //false是不是代表视频正处于暂停状态,
            if (isPaused) {
                //视频暂停
                vr_video.pauseVideo();
            }
            //true是不是代表视频正在播放的状态.
            else {
                //视频播放
                vr_video.playVideo();
            }
            //对标签进行一次操作后,取反
            isPaused = !isPaused;
        }
    }
}
效果图

到这里VR小项目全面完工如有疑问欢迎留言!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值