google vr 入门之VrPanoramaView制作全景图列表


上图的效果想必大家在很多VR App中都见过,下面介绍一种简单的实现方法:

大家可以看到,其实只不过是一个展示图片效果的列表,但是当你滑动到某个位置停止时,对应的条目被激活了,这张图片的全景图便开始动态的显示活动了,原理就是这么简单,那我们如何实现呢?

思路:

1. 首先我们需要一个展示图片的列表(ListView、RecycleView)

2. 列表的每个item展示对应的平面图

3. 对列表进行滑动监听,停止滑动时对应条目的全景图激活显示

4. 页面加载,默认首先要显示第一个item的全景图

思路就是这么简单,这里的全景图我们需要对应的全景图控件来显示,google vr 中有对应的全景图控件VrPanoramaView,google vr 的核心是其父类VrWidgetView,VrPanoramaView和VrVideoView是一对孪生兄弟,分别用来显示全景图和播放全景视频(google vr 视频播放即VrVideoView的使用请参考google vr 入门之制作简易的VR播放器及去除界面控制按钮),今天我们用到的是全景图的显示功能,使用VrPanoramaView非常简单:

// 使用google vr VrPanoramaView 添加的
    compile 'com.google.vr:sdk-audio:1.40.0'
    compile 'com.google.vr:sdk-base:1.40.0'
    compile 'com.google.vr:sdk-panowidget:1.40.0'
我们要用的VrPanoramaView在sdk-panowidget库中,这里使用1.40.0版本是为了去除android 7.0手机没有使用google vr服务弹出警告对话框的问题( 详情请点击)。
准备工作已经完成下面开始写代码了:

展示图片的列表我这里使用RecycleView,activity_main.xml

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.qj.vrpanoramaviewlist.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycleview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>
mRecyclerView = (RecyclerView) findViewById(R.id.recycleview);
//全景图控件初始化
 vrPanoramaView = new VrPanoramaView(this);
 vrPanoramaView.setStereoModeButtonEnabled(false);//眼镜模式按钮禁掉
 vrPanoramaView.setFullscreenButtonEnabled(false); //全屏模式按钮禁掉
 vrPanoramaView.setInfoButtonEnabled(false); //信息按钮禁掉
 vrPanoramaView.setTouchTrackingEnabled(true); //开启手触模式

 options = new VrPanoramaView.Options();
 options.inputType = VrPanoramaView.Options.TYPE_MONO;
为RecycleView准备数据,设置适配器
//准备数据,这里模拟假数据
mDatas = new ArrayList<String>();
for (int i = 'A'; i < 'M'; i++) {
    mDatas.add(String.valueOf((char) i));
}
mSize = mDatas.size();
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new HomeAdapter();
mRecyclerView.setAdapter(mAdapter);
看看HomeAdapter的内容:
class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == PANORAMA_ITEM) {
            return new VrPanoramaViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_panorama, parent, false));
        } else {
            return new FooterHolder(LayoutInflater.from(mContext).inflate(R.layout.item_footer, parent, false));
        }
    }
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (mSize - position > 2) {
            VrPanoramaViewHolder h = (VrPanoramaViewHolder) holder;
            h.tv.setText(mDatas.get(position));
            h.iv.setBackgroundResource(plan[position]);
            if (isFirstTime) {//首次进入要显示第一个item的全景
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(), vr[0]);
                vrPanoramaView.loadImageFromBitmap(bitmap, options);
                h.iv.addView(vrPanoramaView);
                currentPos = 0;
                isFirstTime = false;
            }
        } else if (position == mSize - 1) {
            FooterHolder h = (FooterHolder) holder;
            h.tv.setText("到底啦...");
        }
        Log.e(TAG, "onBindViewHolder: " + position);
    }
    @Override
    public int getItemCount() {
        return mSize;
    }
    @Override
    public int getItemViewType(int position) {
        if (mSize - position > 2) {
            return PANORAMA_ITEM;//全景图类型的item
        } else {
            return FOOTER_ITEM;//底部填充的两个item
        }
    }
    class VrPanoramaViewHolder extends RecyclerView.ViewHolder {//全景图的Holder
        FrameLayout iv;
        TextView tv;
        public VrPanoramaViewHolder(View view) {
            super(view);
            iv = (FrameLayout) view.findViewById(R.id.iv_content);
            tv = (TextView) view.findViewById(R.id.content_name);
        }
    }
    class FooterHolder extends RecyclerView.ViewHolder {//底部填充的Holder
        TextView tv;
        public FooterHolder(View view) {
            super(view);
            tv = (TextView) view.findViewById(R.id.footer_tv);
        }
    }
}
对RecycleView添加滚动监听:
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
    LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
    int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition();
    int pos = lastVisibleItemPosition - 2;
    if (RecyclerView.SCROLL_STATE_IDLE == newState) {//停止滑动
        showPanorama(pos);
    } else {
        if (pos == currentPos || currentPos < 0)//目前正在显示不能移除
            return;
        ViewParent parent = vrPanoramaView.getParent();
        if (parent != null) {//防止在滑动过程中发现被复用的全景图控件
            ViewGroup viewGroup = (ViewGroup) parent;
            viewGroup.removeView(vrPanoramaView);
            currentPos = -1;//此处赋值表示全景图控件没有处在任何item的位置
        }
    }
    super.onScrollStateChanged(recyclerView, newState);
}
这是RecycleView滚动监听回调的方法,在回调中我们得到屏幕中最后一个可见的item的postion,即lastVisibleItemPosition,我们关心的不是这个条目,而是它的上上一个条目,故而才有了int pos = lastVisibleItemPosition - 2;这句代码,pos才是我所关心的(默认一屏幕最少显示三个item最多显示4个item,当前屏幕中最后一个可见的item位于屏幕中第3个或者是第4个的位置,该位置的上上一个item位于屏幕的中间靠上区域内,这个区域的条目显示全景图,用户看着会比较舒服),当停止滑动后,显示全景图:
private void showPanorama(int pos) {
    if (pos == currentPos)//防止重复,做无用功
        return;
    HomeAdapter.VrPanoramaViewHolder childViewHolder = (HomeAdapter.VrPanoramaViewHolder) mRecyclerView.findViewHolderForAdapterPosition(pos);
    ViewParent parent = vrPanoramaView.getParent();
    if (parent != null) {
        ViewGroup viewGroup = (ViewGroup) parent;
        viewGroup.removeView(vrPanoramaView);
    }
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), vr[pos]);
    vrPanoramaView.loadImageFromBitmap(bitmap, options);
    childViewHolder.iv.addView(vrPanoramaView);
    currentPos = pos;
}
该方法是显示RecycleView对应位置item的全景图,全景图也是一个View,只需要通过addView的形式将其添加到对应的item上即可,添加之前加载该item的全景图片。
以上是根据上面提到的思路贴出了对应的代码以及对代码做了简要的分析,实现一个全景图列表其实就是这么简单,这只是一篇入门级别的文章,我们的全景图列表是在Activity中做的,没有搭建项目框架,如果在Fragment页面中加载会比这个复杂一些,后期文章会继续跟进,欢迎大家继续关注!

.apk下载


源码下载

猜你喜欢

转载自blog.csdn.net/github_2011/article/details/72896057