当前位置: 移动技术网 > 科技>人工智能>VR/AR > Android实现VR图片、视频小程序

Android实现VR图片、视频小程序

2020年09月22日  | 移动技术网科技  | 我要评论
Android实现VR图片、视频小程序项目源自黑马程序员编著的《Android企业级项目实战教程》一书第2章程序分为三个部分:主界面、VR图片部分、VR视频部分项目准备创建项目后,首先将主界面所需要的图片vr_bg.png、vr_pic.png、vr_video.png,导入drawable-hdpi文件夹修改清单文件​设置标签中largeHeap属性为true,为程序提供更大的内存空间,避免出现内存溢出​设置标签中theme属性为@style/Theme.AppCompat.Li

Android实现VR图片、视频小程序

项目源自黑马程序员编著的《Android企业级项目实战教程》一书第2章

程序分为三个部分:主界面、VR图片部分、VR视频部分

项目准备

创建项目后,首先将主界面所需要的图片vr_bg.png、vr_pic.png、vr_video.png,导入drawable-hdpi文件夹

vr_bg
vr_video
vr_pic
导入主界面资源

修改清单文件

​ 设置标签中largeHeap属性为true,为程序提供更大的内存空间,避免出现内存溢出

​ 设置标签中theme属性为@style/Theme.AppCompat.Light.NoActionBar,以删除标题栏使程序更美观

主界面制作

编写主界面布局文件,放置两个ImageView控件用于显示”VR图片“以及”VR视频“按钮。

<?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:background="@drawable/vr_bg"
    android:gravity="center"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/iv_pic"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/vr_pic" />
    <ImageView
        android:id="@+id/iv_video"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/vr_video" />
</LinearLayout>

主界面逻辑代码

package com.example.vr;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ImageView iv_pic, iv_video;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    private void init() {
        iv_pic = (ImageView) findViewById(R.id.iv_pic);
        iv_video = (ImageView) findViewById(R.id.iv_video);
        iv_pic.setOnClickListener(this);
        iv_video.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.iv_pic:
                //跳转到VR全景图片界面
                Intent pic = new Intent(MainActivity.this, VRPicActivity.class);
                startActivity(pic);
                break;
            case R.id.iv_video:
                //跳转到VR全景视频界面
                Intent video = new Intent(MainActivity.this,VRVideoActivity.class);
                startActivity(video);
                break;
        }
    }
}

VR图片界面制作

创建一个Empty Activity类,命名为VRPicActivity,布局文件命名为activity_vrpic

项目结构切换为Project选项,在app/src/main文件夹下创建assets文件夹,将全景图片andes.jpg导入该文件夹

andes.jpg
导入图片资源

添加项目所需的库common、commonwidget、panowidget、videowidget

​ 在AndroidStudio中选择File->New->Import Module,把第三方库common库导入项目。

​ 选中项目,右键选择Open Module Settings选项,然后选择Dependencies选项卡,单击右上角的绿色加号并选择Module Dependency选项,把common库加入项目,其余三个库操作同上。

在activity_vrpic中放置VrPanoramaView控件

<?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">
    <com.google.vr.sdk.widgets.pano.VrPanoramaView
        android:id="@+id/vr_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

逻辑代码

package com.example.vr;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

import com.google.vr.sdk.widgets.pano.VrPanoramaEventListener;
import com.google.vr.sdk.widgets.pano.VrPanoramaView;

import java.io.InputStream;

public class VRPicActivity extends AppCompatActivity {
    private VrPanoramaView vrImage;
    private AsyncTask<Void, Void, Bitmap> task;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vrpic);
        init();
    }
    private void init() {
        vrImage = (VrPanoramaView) findViewById(R.id.vr_image);
        vrImage.setEventListener(new VrPanoramaEventListener());//处理图片加载出错的情况
        //2.异步加载全景图片
        task = new AsyncTask<Void, Void, Bitmap>() {
            @Override
            protected Bitmap doInBackground(Void... params) {
                try {
                    // 从assets目录中加载图片
                    InputStream is = getAssets().open("andes.jpg");
                    Bitmap bitmap = BitmapFactory.decodeStream(is);
                    is.close();
                    return bitmap;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                if (bitmap != null) {
                    //加载配置
                    VrPanoramaView.Options options = new VrPanoramaView.Options();
                    //设置图片为立体效果
                    options.inputType = VrPanoramaView.Options.TYPE_STEREO_OVER_UNDER;
                    //加载图片
                    vrImage.loadImageFromBitmap(bitmap, options);
                }
            }
        }.execute();
    }
    @Override
    protected void onResume() {
        super.onResume();
        vrImage.resumeRendering();//恢复渲染
    }
    @Override
    protected void onPause() {
        super.onPause();
        vrImage.pauseRendering();//暂停渲染
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        vrImage.shutdown();     //关闭渲染释放内存
        if (task != null) {
            task.cancel(true); //停止异步任务
            task = null;
        }
    }
}

VR视频界面制作

创建一个Empty Activity类,命名为VRVideoActivity,布局文件命名为activity_vrvideo

将全景视频congo.mp4导入assets文件夹

导入视频资源
(视频因格式限制无法上传,这里仅做演示)

在布局文件activity_vrvideo中放置一个VrVideoView控件,用于显示全景视频,一个SeekBar控件用于显示视频播放的进度条,一个TextView控件用于显示视频播放进度的百分比。

<?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">
    <com.google.vr.sdk.widgets.video.VrVideoView
        android:id="@+id/vr_video"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFF000"
        android:orientation="horizontal">
        <SeekBar
            android:id="@+id/seekbar"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_weight="1" />
        <TextView
            android:id="@+id/seekbar_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:padding="20dp"
            android:text="--:--"
            android:textSize="19sp" />
    </LinearLayout>
</FrameLayout>

逻辑代码

package com.example.vr;

import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.google.vr.sdk.widgets.video.VrVideoEventListener;
import com.google.vr.sdk.widgets.video.VrVideoView;

public class VRVideoActivity extends AppCompatActivity {
    private VrVideoView videoView;
    private AsyncTask<Void, Void, Void> task;
    private TextView seekbarText;
    private SeekBar seekbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vrvideo);
        init();
    }
    private void init() {
        seekbar = (SeekBar) findViewById(R.id.seekbar);
        seekbarText = (TextView) findViewById(R.id.seekbar_text);
        seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
            {
                if (fromUser) {
                    long duration = videoView.getDuration();
                    long newPosition = (long) (progress * 0.01f * duration);
                    videoView.seekTo(newPosition);
                }
            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });
        videoView = (VrVideoView) findViewById(R.id.vr_video);
        videoView.setTag(true);
        videoView.setEventListener(new VrVideoEventListener() {
            @Override
            public void onClick() {
                super.onClick();
                boolean isPlay = (boolean) videoView.getTag();
                if (isPlay) {
                    isPlay = false;
                    videoView.pauseVideo();//暂停播放
                } else {
                    isPlay = true;
                    videoView.playVideo();//继续播放
                }
                videoView.setTag(isPlay);
            }
            //视图画面切换到下一帧时被调用.
            @Override
            public void onNewFrame() {
                super.onNewFrame();
                seekbar.setMax(100);
                long duration = videoView.getDuration();//获取视频时长,单位毫秒
                long currentPosition = videoView.getCurrentPosition();//获取当前位置
                int percent = (int) (currentPosition * 100f / duration + 0.5f);
                seekbar.setProgress(percent);
                seekbarText.setText(percent + "%");
            }
            @Override
            public void onLoadSuccess() {
                super.onLoadSuccess();
                Toast.makeText(VRVideoActivity.this, "开始播放", Toast.LENGTH_SHORT)
                        .show();
                seekbar.setMax(100);
                seekbar.setProgress(0);
                seekbarText.setText("0%");
            }
            @Override
            public void onLoadError(String errorMessage) {
                super.onLoadError(errorMessage);
                Toast.makeText(VRVideoActivity.this, "播放出错", Toast.LENGTH_SHORT)
                        .show();
            }
            @Override
            public void onCompletion() {
                super.onCompletion();
                seekbar.setMax(100);
                seekbar.setProgress(100);
                seekbarText.setText("100%");
            }
        });
        //创建异步任务
        task = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                String fileName = "congo.mp4";
                VrVideoView.Options option = new VrVideoView.Options();
                option.inputFormat = VrVideoView.Options.FORMAT_DEFAULT;//非流媒体
                option.inputType = VrVideoView.Options.TYPE_STEREO_OVER_UNDER;//3D效果
                try {
                    //从资产目录加载视频
                    videoView.loadVideoFromAsset(fileName, option);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                Toast.makeText(VRVideoActivity.this, "加载成功开始播放",
                        Toast.LENGTH_SHORT).show();
            }
        }.execute();
    }


    //细节一.切换模式造成屏幕变黑
    @Override
    protected void onResume() {
        super.onResume();
        videoView.resumeRendering();//重新渲染
    }

    @Override
    protected void onPause() {
        super.onPause();
        videoView.pauseRendering();//停止渲染
    }

    //细节二.AsyncTask处理
    @Override
    protected void onDestroy() {
        super.onDestroy();
        videoView.shutdown();//停止
        if (task != null) {
            task.cancel(true);
            task = null;
        }
    }
}

此时调试运行程序会闪退,判断为依赖问题

解决方法:

1.降低build.gradle(:app)中minSDKVersion版本

defaultConfig {
    minSdkVersion 19
}

2.更改build.gradle(:app)中依赖

dependencies {
    implementation project(path: ':common')
    implementation project(path: ':commonwidget')
    implementation project(path: ':panowidget')
    implementation project(path: ':videowidget')
}

改为使用

dependencies {
    compile 'com.google.vr:sdk-audio:1.10.0'
    compile 'com.google.vr:sdk-base:1.10.0'
    compile 'com.google.vr:sdk-common:1.10.0'
    compile 'com.google.vr:sdk-commonwidget:1.10.0'
    compile 'com.google.vr:sdk-panowidget:1.10.0'
    compile 'com.google.vr:sdk-videowidget:1.10.0'
}

3.更改build.gradle(‘项目名称’)中buildscript下dependencies的classpath

classpath 'com.android.tools.build:gradle:3.5.1'

并在buildscript下的repositories和allprojects下的repositories两处添加

maven {
    url "http://maven.aliyun.com/nexus/content/groups/public/"
}

此时虚拟机成功运行程序。

总结:在实际学习中可能遇到开发工具、库等版本不兼容的问题,需要多尝试各种方法。

本文地址:https://blog.csdn.net/qq_23604153/article/details/108739303

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网