11.接下来就要开始编写VrPanoFragment全景图的类了,首先修改继承改成我们自己写的BaseFragment并实现他的两个方法
/**
* Date:2017/3/16
* author:陈箫阳ChenXiaoYang
* furction:展示VR全景图Fragment列表
*/
public class VrPanoFragment extends BaseFragment {
//创建自己的LayoutManager,使用默认的即可
@Override
public RecyclerView.LayoutManager getLayoutManager() {
return new LinearLayoutManager(getActivity());
}
//创建自己的适配器
@Override
public RecyclerView.Adapter getAdapter() {
//把图片资源数据放入适配器中
return new VrPanoAdapter(ImageUrGetter.getImageItems());
}
}
写到这里会有报红,需要创建三个类,遵从从内到外创建的原则,首先创建ImageUrGetter类,返回VrPanoFragment类并实现一个方法,将返回的数据改为List
/**
* Date:2017/3/18
* author:陈箫阳ChenXiaoYang
* furction:
*/
public class ImageUrGetter {
public static List getImageItems() {
return sImageItems;
}
}
此时ImageItem会报红,使用快捷键创建ImageItem类
/**
* Date:2017/3/16
* author:陈箫阳ChenXiaoYang
* furction:这就是一个bean类
*/
public class ImageItem {
//标题
public String title;
//图片的Url
public String url;
//音乐的Url,也是一个网址
public String mp3;
//构造有参方法
public ImageItem(String title, String url, String mp3) {
this.title = title;
this.url = url;
this.mp3 = mp3;
}
}
返回ImageUrGetter类,首先创建一个集合对象,泛型为自己的Bean类,然后New一个Bean类,有三个参数1.字符串:名称 2.全景图图片的网址 3.播放音乐的网址,不需要可以置为null
/**
* Date:2017/3/16
* author:陈箫阳ChenXiaoYang
* furction:VR全景图的网址数据,通过抓包获取到,在本类中装入集合
*/
public class ImageUrGetter {
public static List getImageItems() {
List items = new ArrayList();
items.add(new ImageItem("滕王阁", "http://media.qicdn.detu.com/pano177051472357986990056825/thumb/500_500/panofile.jpg", "http://media.qicdn.detu.com/@/13363707-8857-C248-3CE1-64F2F24291636/source/145049/o_1arbdk2apj37df16up16um196j7.mp3"));
items.add(new ImageItem("巴山大峡谷-云海日出", "http://media.qicdn.detu.com/@/17596710-5661-0192-EDC8-81F89376806/source/142048/o_1aqd3brm71svb11gqh5la5bjj17.jpg", "http://media.qicdn.detu.com/@/17596710-5661-0192-EDC8-81F89376806/source/128321/o_1amb55jqq13ma8po16aogvdrjkc.mp3"));
items.add(new ImageItem("厦大", "http://media.qicdn.detu.com/pano781791479224712452691293/thumb/500_500/panofile.jpg", null));
items.add(new ImageItem("西南大学经济管理学院", "http://media.qicdn.detu.com/pano573341478189386216286405/thumb/500_500/panofile.jpg", null));
items.add(new ImageItem("辽宁工业大学", "http://media.qicdn.detu.com/pano476831467201488386232805/thumb/500_500/panofile.jpg", null));
items.add(new ImageItem("西安海棠职业学院", "http://media.qicdn.detu.com/pano532201469338026348840893/thumb/500_500/panofile.jpg", "http://media.qicdn.detu.com/@/18192570-5756-0D36-9533-2416F77090543/source/135547/o_1aodn4afsqclli11jm5tr22kg7.mp3"));
return items;
}
}
回到VrPanoFragment类VrPanoAdapter会报红使用快捷键创建VrPanoAdapter适配器类,全景图Adapter的RecyclerView适配器需要继承BaseQuickAdapter开源项目的类,首先需要关联LibBaseAdapterUpdate包需要自己下载
步骤:点击File
然后按住control+alt+shift+s会弹出一个Project Structure点击所要添加的项目,点击Dependencies,点击+号,选择Module Dependency
使VrPanoAdapter适配器继承开源框架的BaseQuickAdapter,这里会报红是需要创建一些构造方法
/**
* Date:2017/3/16
* author:陈箫阳ChenXiaoYang
* furction:全景图Adapter的RecyclerView适配器,这里的BaseQuickAdapter是开项目的类
* RecyclerView适配器的一个开源项目,简化RecyclerView适配器的代码编写,内部封装了点击等接口
*/
public class VrPanoAdapter extends BaseQuickAdapter {
//A.决定了Item的布局样式
public VrPanoAdapter(List imageItems) {
super(R.layout.vr_pano_list_item, imageItems);
}
//A.把数据填充到布局上
@Override
protected void convert(BaseViewHolder helper, ImageItem item) {
}
}
此时R.layout.vr_pano_list_item会报红,使用快捷键创建vr_pano_list_item布局文件,在这里需要在mipmap-mdpi中放一些需要用的图片
xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="170dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="5dp"
android:elevation="5dp"
android:orientation="vertical"
app:cardCornerRadius="10dp">
<LinearLayout
android:id="@+id/ll_item_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingTop="2dp">
<ImageView
android:id="@+id/iv_pano"
android:layout_width="match_parent"
android:layout_height="130dp"
android:scaleType="fitXY"
android:src="@mipmap/andes"/>
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是标题"
android:textColor="#0095ff"
android:textSize="18sp"/>
LinearLayout>
android.support.v7.widget.CardView>
在这里用了一个CardView的包所以我们需要导入这个包
步骤:按住control+alt+shift+s会弹出一个Project Structure点击所要添加的项目,点击Dependencies,点击+号,选择Library Dependency
在与主类同级出新建一个包名为bean,将ImageItem类放入包中,再新建一个包名为utli,将ImageUrGetter类放入包中
此时回到VrPanoAdapter适配器类
//A.把数据填充到布局上
@Override
protected void convert(BaseViewHolder helper, ImageItem item) {
//A.获取ImageView并显示图片到ImageView上
ImageView iv_pano = helper.getView(R.id.iv_pano);
//A.获取到上下文
Context mContext = helper.getConvertView().getContext();
}
在这里我们要用到Glide的开源框架,所以要导入
com.github.bumptech.glide:glide:3.7.0包
步骤:按住control+alt+shift+s会弹出一个Project Structure点击所要添加的项目,点击Dependencies,点击+号,选择Library Dependency
//A.使用开元框架Glide把url网址网址图片设置好,必须导入:compile 'com.github.bumptech.glide:glide:3.7.0'
//注意加权限
Glide.with(mContext).load(item.url).into(iv_pano);
使用开源框架Glide需要添加网路权限,打开清单文件添加权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE”/>
此时回到VrPanoAdapter适配器类
//A.设置标题到TextView 参数1.控件ID 2.文本
helper.setText(R.id.tv_title, item.title);
效果图
继续编写VrPanoAdapter适配器类在这里需要使用开源框架的点击事件
首先在convert方法中设置监听事件
//RecyclerView没有点击事件的方法,如果需要可以给内部控件设置点击事件
View view = helper.getView(R.id.ll_item_main);
//把数据以标签的形式设置给控件
view.setTag(item);
//不以内部类的形式去写是为了节约资源
view.setOnClickListener(listener);
然后在convert方法下设置Item的点击事件
//设置了Item点击的监听对象,这样只写了一个对象,节约内存
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建意图对象 参数 1.上下文 2.要跳转的类
Intent intent = new Intent(v.getContext(), ImageDetailActivity.class);
//从控件中取出数据
ImageItem item= (ImageItem) v.getTag();
//拿到数据里面的图片网址和音乐网址,通过Intent传给全景图的详情页
intent .putExtra("url",item.url);
intent.putExtra("mp3",item.mp3);
//开启跳转意图
v.getContext().startActivity(intent);
}
};
在这里ImageDetailActivity会报红,创建名为ImageDetailActivity的类用于跳转显示全景图,并创建activity_image_detail.xml布局文件
在这里需要在与主类同级处新建一个activity包将ImageDetailActivity放入包中
12.显示全景图首先需要搭建环境,因为使用VR的资源很消耗内存,所以我们为了避免OOM的问题,要把警报权限提高,从192提高到512m在AndroidManifest.xml清单文件中添加:android:largeHeap=“true”
android:largeHeap=“true"
android VR 资源下载网址:
VR资源下载网址
打开android VR 资源下载网址下载下图中的文件
下载好的是一个压缩包,解压压缩包得到下图中的文件
要导入VR资源common commonwidget panowidget包
打开gvr-android-sdk-master打开libraries
在Studio中导入
步骤:点击File
然后按住control+alt+shift+s会弹出一个Project Structure点击所要添加的项目,点击Dependencies,点击+号,选择Module Dependency
最后在build.gradie文件中添加
compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
并修改版本号为19:
minSdkVersion 19
如果不修改会报下图中的错误,这个错是说最低版本不能低于16,故要修改版本号,最好修改到19
13.打开ImageDetailActivity类的布局文件activity_image_detail.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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
tools:context="com.example.vr_text.ImageDetailActivity">
<com.google.vr.sdk.widgets.pano.VrPanoramaView
android:id="@+id/vr_pano"
android:layout_width="match_parent"
android:layout_height="match_parent">
com.google.vr.sdk.widgets.pano.VrPanoramaView>
<ProgressBar
android:id="@+id/pb_loading"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
RelativeLayout>
14.打开ImageDetailActivity类,设置全景图跳转
//根据点击事件跳转到VR全景图的页面
public class ImageDetailActivity extends AppCompatActivity {
private VrPanoramaView mVrPanoramaView;
private ProgressBar mProgressBar;
private MediaPlayer mMediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_detail);
//初始化ActionBar
initActionBar();
//初始化PanoView
initPanoView();
}
private void initActionBar() {
//得到ActionBar对象
ActionBar actionBar = getSupportActionBar();
//设置左上角的箭头
actionBar.setDisplayHomeAsUpEnabled(true);
}
//设置点击事件
@Override
public boolean onOptionsItemSelected(MenuItem item) {
//给左上角的箭头设置逻辑,点击是推出页面
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
private void initPanoView() {
//初始化控件
mVrPanoramaView = (VrPanoramaView) findViewById(R.id.vr_pano);
mProgressBar = (ProgressBar) findViewById(R.id.pb_loading);
//获取传过来的Intent,取出传过来的值
Intent intent = getIntent();
String url = intent.getStringExtra("url");
String mp3 = intent.getStringExtra("mp3");
//使用媒体控件播放音乐
initPlayer(mp3);
//OKGo开源框架,以OkHp为底层,记得在Applincation进行初始化
}
private void initPlayer(String mp3) {
}
}
这里要使用OKGo网络请求,所以要添加OKGo的包打开build.gradle文件添加:compile 'com.lzy.net:okgo:2.1.3'
compile 'com.lzy.net:okgo:2.1.3'
15.创建一个类Applincation类并继承Application,用于网络框架OKGo的初始化
/**
* Date:2017/3/17
* author:陈箫阳ChenXiaoYang
* furction:进行网络框架OKGo的初始化,记得在清单文件中注册MyApplication
*/
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//OKGo全局初始化
OkGo.init(this);
//设置网络请求的参数
OkGo.getInstance().setConnectTimeout(3000)//连接超时
.setReadTimeOut(3000)//读取超时
.setWriteTimeOut(3000)//写入超时
.setCacheMode(CacheMode.IF_NONE_CACHE_REQUEST)//设置缓存模式,从类点击进去,可以看到具体情况
.setCacheTime(CacheEntity.CACHE_NEVER_EXPIRE)//设置缓存时间
.setRetryCount(3);//设置网络请求失败的重试次数
}
}
打开清单文件注册MyApplication,在清单文件中添加:android:name=".MyApplication”
android:name=".MyApplication"
16.回到ImageDetailActivity类
//OKGo开源框架,以OkHp为底层,记得在Applincation进行初始化
OkGo.get(url)//使用get的方式请求网络,url是网络
.cacheKey(url)
.execute(new BitmapCallback() {
@Override
public void onSuccess(Bitmap bitmap, Call call, Response response) {
//使进度条消失
mProgressBar.setVisibility(VrPanoramaView.GONE);
//创建VrPanoramaView.Options,去决定VR是普通效果还是立体效果
VrPanoramaView.Options options = new VrPanoramaView.Options();
//VrPanoramaView.Options.TYPE_MONO普通效果
options.inputType = VrPanoramaView.Options.TYPE_MONO;
//使用Vr框架加载Bitmap 参数1.Bitmap 2.VrPanoramaView.Options对象
mVrPanoramaView.loadImageFromBitmap(bitmap, options);
}
});
}
private void initPlayer(String mp3) {
//做非空判断
if (mp3 != null) {
//创建多媒体对象
mMediaPlayer = new MediaPlayer();
//设置播放为音频模式
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
//设置播放的数据源 参数1.上下文 2.URl
mMediaPlayer.setDataSource(this, Uri.parse(mp3));
//准备播放
mMediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//当失去焦点时,回调
@Override
protected void onPause() {
super.onPause();
//暂停渲染和显示
mVrPanoramaView.pauseRendering();
//判断MediaPlayer是否为空
if (mMediaPlayer != null) {
//不为null,暂停播放
mMediaPlayer.pause();
}
}
//当获取焦点时,回调
@Override
protected void onResume() {
super.onResume();
//继续渲染显示
mVrPanoramaView.resumeRendering();
//判断MediaPlayer是否为空
if (mMediaPlayer != null) {
//不为null,开始播放音乐视屏
mMediaPlayer.start();
}
}
//当Acyivity销毁时,回调
@Override
protected void onDestroy() {
super.onDestroy();
//关闭渲染视图
mVrPanoramaView.shutdown();
//判断MediaPlayer是否为空
if (mMediaPlayer != null) {
//不为空停止音乐
mMediaPlayer.stop();
//释放资源
mMediaPlayer.release();
//把对象置为空
mMediaPlayer = null;
}
}
此时VR全景图的点击就做好了
效果图