欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

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

程序员文章站 2022-03-15 21:33:01
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文件夹

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

修改清单文件

​ 设置标签中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导入该文件夹

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

添加项目所需的库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文件夹

Android实现VR图片、视频小程序
(视频因格式限制无法上传,这里仅做演示)

在布局文件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