Android 自定义 SurfaceView 方向无法从纵向旋转到横向
Android custom SurfaceView orientation can't rotate from portrait to landscape
我是一名新 android 应用工程师。我正在尝试制作一个 vulkan 渲染后端演示,它使用 SurfaceView 作为 android Java 代码上的视图。我也使用 GLSurfaceView 制作了 gles 渲染后端演示。在应用程序代码中,我使用 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) API 将 activity 从默认纵向设置为横向。但它在 SurfaceView 上不起作用,而在 GLSurfaceView 上起作用。
我用renderdoc抓取渲染结果,图片是横向布局的(和gles后端一样的布局)。我怀疑 activity 或 window 上的某些设置有问题,但无法找出根本原因。有人可以帮助解决问题吗?
这是 Java 源代码。
package com.example.graphicsdebugger;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
//////////////////////////////////////////////Jerome///////////////////////////////////////////////
import android.view.SurfaceHolder;
import android.view.View;
import android.view.WindowManager;
import android.util.Log;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class DemoFullscreenActivity extends AppCompatActivity /*implements Serializable */{
//////////////////////////////////////////////Jerome///////////////////////////////////////////
private static final String TAG = "9527";
private static final int UNKNOWN_RENDERER = -1;
private static final int FORWARD_RENDERER = 0;
private static final int DEFERRED_RENDERER = 1;
private static final int SET_UNKNOWN = -1;
private static final int SET_MODEL = 0;
private static final int SET_SSAO = 1;
private static final int SET_SSSSS = 2;
private static final int SET_SSAO_RADIUS = 3;
private static final int SET_SSAO_BIAS = 4;
private static final int SET_SSAO_COEFFICIENT = 5;
private static final int SET_SSAO_KERNEL_SIZE = 6;
private static final int SET_BACKEND = 7;
private boolean mBackend = false;
private GLSurfaceView mGLSurfaceView;
private VKSurfaceView mVKSurfaceView;
protected static final float FLIP_DISTANCE = 50;
GestureDetector mDetector;
DemoRenderer mRender;
///////////////////////////////////////////////////////////////////////////////////////////////
private void setSSAORadiusSeekBar() {
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarRadius);
// set default value
seekBar.setProgress(5);
TextView textView = (TextView) findViewById(R.id.textRadius);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText("Radius:" + Integer.toString(progress));
mRender.SetInt(SET_SSAO_RADIUS, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
private void setSSAOBiasSeekBar() {
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarBias);
// set default value
seekBar.setProgress(5);
TextView textView = (TextView) findViewById(R.id.textBias);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText("Bias:" + Integer.toString(progress));
mRender.SetInt(SET_SSAO_BIAS, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
private void setSSAOCoefficientSeekBar() {
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarCoefficient);
// set default value
seekBar.setProgress(150);
TextView textView = (TextView) findViewById(R.id.textCoefficient);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText("Coefficient:" + Integer.toString(progress));
mRender.SetInt(SET_SSAO_COEFFICIENT, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
private void setSSAOKernelSizeSeekBar() {
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarKernelSize);
// set default value
seekBar.setProgress(2);
TextView textView = (TextView) findViewById(R.id.textKernelSize);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText("Kernel Size:" + Integer.toString(progress * 8));
mRender.SetInt(SET_SSAO_KERNEL_SIZE, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
private void setSSAOCheckBox() {
CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
ssao.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = ((CheckBox)v).isChecked();
mRender.SetSSAO(checked);
}
});
}
private void setSSSSSCheckBox() {
CheckBox sssss = (CheckBox) findViewById(R.id.sssss_check_box);
sssss.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = ((CheckBox)v).isChecked();
mRender.SetSSSSS(checked);
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo_fullscreen);
//////////////////////////////////////////////Jerome///////////////////////////////////////
// 设置横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 隐藏导航栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 隐藏应用标题栏
getSupportActionBar().hide();
setSSAOCheckBox();
setSSSSSCheckBox();
setSSAORadiusSeekBar();
setSSAOBiasSeekBar();
setSSAOCoefficientSeekBar();
setSSAOKernelSizeSeekBar();
rendererDraw();
///////////////////////////////////////////////////////////////////////////////////////////
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
//////////////////////////////////////////////Jerome///////////////////////////////////////////
private void rendererDraw() {
Bundle bundle = getIntent().getExtras();
if (bundle == null) return;
if (bundle.containsKey("Backend")) {
mBackend = bundle.getBoolean("Backend");
}
if (mBackend) { // Vulkan
Log.d("9527", "init VKSurfaceView");
mVKSurfaceView = (VKSurfaceView)findViewById(R.id.vk_surface_view);
SurfaceHolder holder = mVKSurfaceView.getHolder();
mRender = new DemoRenderer(this, holder.getSurface());
mVKSurfaceView.setRenderer(mRender);
} else { // GLES
Log.d("9527", "init GLSurfaceView");
mGLSurfaceView = (GLSurfaceView)findViewById(R.id.gl_surface_view);
mGLSurfaceView.setEGLContextClientVersion(2);
SurfaceHolder holder = mGLSurfaceView.getHolder();
mRender = new DemoRenderer(this, holder.getSurface());
mGLSurfaceView.setRenderer(mRender);
mGLSurfaceView.getAlpha();
}
mRender.SetInt(SET_SSAO_RADIUS, 5);
mRender.SetInt(SET_SSAO_BIAS, 5);
mRender.SetInt(SET_SSAO_COEFFICIENT, 150);
mRender.SetInt(SET_SSAO_KERNEL_SIZE, 2);
int renderer = UNKNOWN_RENDERER;
if (bundle.containsKey("Renderer")) {
renderer = bundle.getInt("Renderer");
mRender.SetRenderer(renderer);
}
if (bundle.containsKey("Backend")) {
mRender.SetInt(SET_BACKEND, mBackend ? 1 : 0);
}
if (renderer != DEFERRED_RENDERER) {
CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
ssao.setEnabled(false);
} else if (bundle.containsKey("SSAO")) {
boolean isChecked = bundle.getBoolean("SSAO");
mRender.SetSSAO(isChecked);
CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
ssao.setChecked(isChecked);
}
if (renderer != DEFERRED_RENDERER) {
CheckBox sssss = (CheckBox) findViewById(R.id.sssss_check_box);
sssss.setEnabled(false);
} else if (bundle.containsKey("SSSSS")) {
mRender.SetSSSSS(bundle.getBoolean("SSSSS"));
}
if (bundle.containsKey("Model")) {
mRender.SetModel(bundle.getInt("Model"));
}
mDetector = new GestureDetector(this, new GestureDetector.OnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
/**
*
* e1 The first down motion event that started the fling. e2 The
* move motion event that triggered the current onFling.
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (e1.getX() - e2.getX() > FLIP_DISTANCE) {
Log.d(TAG, "Slide left...");
return true;
}
if (e2.getX() - e1.getX() > FLIP_DISTANCE) {
Log.d(TAG, "Slide right...");
return true;
}
if (e1.getY() - e2.getY() > FLIP_DISTANCE) {
Log.d(TAG, "Slide up...");
return true;
}
if (e2.getY() - e1.getY() > FLIP_DISTANCE) {
Log.d(TAG, "Slide down...");
return true;
}
Log.d(TAG, e2.getX() + " " + e2.getY());
return false;
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//Log.d(TAG, "===> MainActivity call dispatchTouchEvent()");
//Log.d(TAG, "===> super.dispatchTouchEvent() default return true");
//Log.d(TAG, "--------------------------------------------------");
return super.dispatchTouchEvent(ev);
}
@Override
public void onUserInteraction() {
//Log.d(TAG, "===> MainActivity call onUserInteraction()");
//Log.d(TAG, "--------------------------------------------------");
super.onUserInteraction();
}
float Finger_0_DownX = 0;
float Finger_0_DownY = 0;
float Finger_1_DownX = 0;
float Finger_1_DownY = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int mActivePointerId =0;
int idx = event.findPointerIndex(mActivePointerId);
if (idx >=0 ) {
Finger_0_DownX = event.getX(idx);
Finger_0_DownY = event.getY(idx);
mRender.setFingerDown(0, Finger_0_DownX, Finger_0_DownY);
}
break;
case MotionEvent.ACTION_UP:
Finger_0_DownX = 0.0f;
Finger_0_DownY = 0.0f;
mRender.setFingerUp(0);
break;
default:
break;
}
switch(event.getActionMasked()) {
case MotionEvent.ACTION_POINTER_DOWN:
int mActivePointerId = 1;
int idx = event.findPointerIndex(mActivePointerId);
if (idx >=0 ) {
Finger_1_DownX = event.getX(idx);
Finger_1_DownY = event.getY(idx);
mRender.setFingerDown(1, Finger_1_DownX, Finger_1_DownY);
}
break;
case MotionEvent.ACTION_POINTER_UP:
Finger_1_DownX = 0.0f;
Finger_1_DownY = 0.0f;
mRender.setFingerUp(1);
break;
default:
break;
}
if (Finger_0_DownX != 0.0f && Finger_0_DownY != 0.0f) {
int mActivePointerId =0;
int idx = event.findPointerIndex(mActivePointerId);
if (idx >=0 ) {
mRender.setFingerPosition(0, event.getX(idx), event.getY(idx));
}
}
if (Finger_1_DownX != 0.0f && Finger_1_DownY != 0.0f) {
int mActivePointerId = 1;
int idx = event.findPointerIndex(mActivePointerId);
if (idx >=0 ) {
mRender.setFingerPosition(1, event.getX(idx), event.getY(idx));
}
}
return mDetector.onTouchEvent(event);
}
///////////////////////////////////////////////////////////////////////////////////////////////
}
这是 activity 布局。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frameLayout3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/fullscreenBackgroundColor"
android:theme="@style/ThemeOverlay.GraphicsDebugger.FullscreenContainer"
tools:context=".DemoFullscreenActivity">
<android.opengl.GLSurfaceView
android:id="@+id/gl_surface_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<com.example.graphicsdebugger.VKSurfaceView
android:id="@+id/vk_surface_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<CheckBox
android:id="@+id/ssao_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="SSAO"
app:layout_constraintBottom_toTopOf="@+id/sssss_check_box"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.019"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.728" />
<CheckBox
android:id="@+id/sssss_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="272dp"
android:text="SSSSS"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.019"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/textRadius"
android:layout_width="72dp"
android:layout_height="35dp"
android:text="Radius:5"
app:layout_constraintBottom_toBottomOf="@+id/gl_surface_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.175"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.101" />
<TextView
android:id="@+id/textCoefficient"
android:layout_width="111dp"
android:layout_height="35dp"
android:text="Coefficient:150"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.419"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.101" />
<TextView
android:id="@+id/textBias"
android:layout_width="72dp"
android:layout_height="35dp"
android:text="Bias:5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.68"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.101" />
<TextView
android:id="@+id/textKernelSize"
android:layout_width="111dp"
android:layout_height="35dp"
android:text="Kernel Size:16"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.925"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.101" />
<SeekBar
android:id="@+id/seekBarKernelSize"
android:layout_width="146dp"
android:layout_height="28dp"
android:max="8"
android:min="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.935"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.043" />
<SeekBar
android:id="@+id/seekBarCoefficient"
android:layout_width="146dp"
android:layout_height="28dp"
android:max="300"
android:min="100"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.408"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.041" />
<SeekBar
android:id="@+id/seekBarRadius"
android:layout_width="146dp"
android:layout_height="28dp"
android:max="100"
android:min="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/gl_surface_view"
app:layout_constraintHorizontal_bias="0.141"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.04" />
<SeekBar
android:id="@+id/seekBarBias"
android:layout_width="146dp"
android:layout_height="28dp"
android:max="30"
android:min="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/gl_surface_view"
app:layout_constraintHorizontal_bias="0.675"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.041" />
</androidx.constraintlayout.widget.ConstraintLayout>
这是AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.graphicsdebugger">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.GraphicsDebugger">
<activity android:name=".RendererSettingsActivity"></activity>
<activity
android:name=".DemoFullscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_demo_fullscreen"
android:theme="@style/Theme.GraphicsDebugger.Fullscreen"
android:launchMode="singleInstance"/>
<activity android:name=".RenderingEngineActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
在 AndroidManifest.xml 的 <activity>
标签中,添加行 android:screenOrientation="portrait"
.
参考https://www.geeksforgeeks.org/designing-the-landscape-and-portrait-mode-of-application-in-android/添加横向布局。布局文件将位于 res/layout-land/ 目录。布局 xml 文件与 res/layout 目录中的文件同名。该文件名将在 setContentView(R.layout.activity_layout_name) 中使用。 activity 的 landsacpe/portrait 布局选择在 AndroidManifest.xml 参数 android:screenOrientation="value" 中设置,作为实验值,而值要么是横向的,要么是纵向的。当我们在AndroidManifest.xml中选择纵向模式时,对应的activity会在res/layout目录下找到布局文件,并设置ContentView。选择景观时,它将在res/layout-land目录中找到布局文件。所以在res/layout和res/layout-land目录下,layout文件名应该是一样的,因为我们在activity里调用了setContentViewAPI,参数应该都适合res/layout 和 res/layout-land 目录中的文件。
我需要在横向布局中设置我的 activity,因此在 AndroidManifest.xml 对应的 activity 中,我设置 android:screenOrientation="横向"。
然后 Activity 代码将 setContentView 使用 res/layout-land 目录中的布局文件。在横向布局 xml 文件中,我有两个视图,一个是 GLSurfaceView,另一个是 VKSurfaceView。
我是一名新 android 应用工程师。我正在尝试制作一个 vulkan 渲染后端演示,它使用 SurfaceView 作为 android Java 代码上的视图。我也使用 GLSurfaceView 制作了 gles 渲染后端演示。在应用程序代码中,我使用 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) API 将 activity 从默认纵向设置为横向。但它在 SurfaceView 上不起作用,而在 GLSurfaceView 上起作用。
我用renderdoc抓取渲染结果,图片是横向布局的(和gles后端一样的布局)。我怀疑 activity 或 window 上的某些设置有问题,但无法找出根本原因。有人可以帮助解决问题吗?
这是 Java 源代码。
package com.example.graphicsdebugger;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
//////////////////////////////////////////////Jerome///////////////////////////////////////////////
import android.view.SurfaceHolder;
import android.view.View;
import android.view.WindowManager;
import android.util.Log;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class DemoFullscreenActivity extends AppCompatActivity /*implements Serializable */{
//////////////////////////////////////////////Jerome///////////////////////////////////////////
private static final String TAG = "9527";
private static final int UNKNOWN_RENDERER = -1;
private static final int FORWARD_RENDERER = 0;
private static final int DEFERRED_RENDERER = 1;
private static final int SET_UNKNOWN = -1;
private static final int SET_MODEL = 0;
private static final int SET_SSAO = 1;
private static final int SET_SSSSS = 2;
private static final int SET_SSAO_RADIUS = 3;
private static final int SET_SSAO_BIAS = 4;
private static final int SET_SSAO_COEFFICIENT = 5;
private static final int SET_SSAO_KERNEL_SIZE = 6;
private static final int SET_BACKEND = 7;
private boolean mBackend = false;
private GLSurfaceView mGLSurfaceView;
private VKSurfaceView mVKSurfaceView;
protected static final float FLIP_DISTANCE = 50;
GestureDetector mDetector;
DemoRenderer mRender;
///////////////////////////////////////////////////////////////////////////////////////////////
private void setSSAORadiusSeekBar() {
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarRadius);
// set default value
seekBar.setProgress(5);
TextView textView = (TextView) findViewById(R.id.textRadius);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText("Radius:" + Integer.toString(progress));
mRender.SetInt(SET_SSAO_RADIUS, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
private void setSSAOBiasSeekBar() {
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarBias);
// set default value
seekBar.setProgress(5);
TextView textView = (TextView) findViewById(R.id.textBias);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText("Bias:" + Integer.toString(progress));
mRender.SetInt(SET_SSAO_BIAS, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
private void setSSAOCoefficientSeekBar() {
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarCoefficient);
// set default value
seekBar.setProgress(150);
TextView textView = (TextView) findViewById(R.id.textCoefficient);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText("Coefficient:" + Integer.toString(progress));
mRender.SetInt(SET_SSAO_COEFFICIENT, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
private void setSSAOKernelSizeSeekBar() {
SeekBar seekBar = (SeekBar) findViewById(R.id.seekBarKernelSize);
// set default value
seekBar.setProgress(2);
TextView textView = (TextView) findViewById(R.id.textKernelSize);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText("Kernel Size:" + Integer.toString(progress * 8));
mRender.SetInt(SET_SSAO_KERNEL_SIZE, progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
}
private void setSSAOCheckBox() {
CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
ssao.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = ((CheckBox)v).isChecked();
mRender.SetSSAO(checked);
}
});
}
private void setSSSSSCheckBox() {
CheckBox sssss = (CheckBox) findViewById(R.id.sssss_check_box);
sssss.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean checked = ((CheckBox)v).isChecked();
mRender.SetSSSSS(checked);
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo_fullscreen);
//////////////////////////////////////////////Jerome///////////////////////////////////////
// 设置横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 隐藏导航栏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 隐藏应用标题栏
getSupportActionBar().hide();
setSSAOCheckBox();
setSSSSSCheckBox();
setSSAORadiusSeekBar();
setSSAOBiasSeekBar();
setSSAOCoefficientSeekBar();
setSSAOKernelSizeSeekBar();
rendererDraw();
///////////////////////////////////////////////////////////////////////////////////////////
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
//////////////////////////////////////////////Jerome///////////////////////////////////////////
private void rendererDraw() {
Bundle bundle = getIntent().getExtras();
if (bundle == null) return;
if (bundle.containsKey("Backend")) {
mBackend = bundle.getBoolean("Backend");
}
if (mBackend) { // Vulkan
Log.d("9527", "init VKSurfaceView");
mVKSurfaceView = (VKSurfaceView)findViewById(R.id.vk_surface_view);
SurfaceHolder holder = mVKSurfaceView.getHolder();
mRender = new DemoRenderer(this, holder.getSurface());
mVKSurfaceView.setRenderer(mRender);
} else { // GLES
Log.d("9527", "init GLSurfaceView");
mGLSurfaceView = (GLSurfaceView)findViewById(R.id.gl_surface_view);
mGLSurfaceView.setEGLContextClientVersion(2);
SurfaceHolder holder = mGLSurfaceView.getHolder();
mRender = new DemoRenderer(this, holder.getSurface());
mGLSurfaceView.setRenderer(mRender);
mGLSurfaceView.getAlpha();
}
mRender.SetInt(SET_SSAO_RADIUS, 5);
mRender.SetInt(SET_SSAO_BIAS, 5);
mRender.SetInt(SET_SSAO_COEFFICIENT, 150);
mRender.SetInt(SET_SSAO_KERNEL_SIZE, 2);
int renderer = UNKNOWN_RENDERER;
if (bundle.containsKey("Renderer")) {
renderer = bundle.getInt("Renderer");
mRender.SetRenderer(renderer);
}
if (bundle.containsKey("Backend")) {
mRender.SetInt(SET_BACKEND, mBackend ? 1 : 0);
}
if (renderer != DEFERRED_RENDERER) {
CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
ssao.setEnabled(false);
} else if (bundle.containsKey("SSAO")) {
boolean isChecked = bundle.getBoolean("SSAO");
mRender.SetSSAO(isChecked);
CheckBox ssao = (CheckBox) findViewById(R.id.ssao_check_box);
ssao.setChecked(isChecked);
}
if (renderer != DEFERRED_RENDERER) {
CheckBox sssss = (CheckBox) findViewById(R.id.sssss_check_box);
sssss.setEnabled(false);
} else if (bundle.containsKey("SSSSS")) {
mRender.SetSSSSS(bundle.getBoolean("SSSSS"));
}
if (bundle.containsKey("Model")) {
mRender.SetModel(bundle.getInt("Model"));
}
mDetector = new GestureDetector(this, new GestureDetector.OnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
/**
*
* e1 The first down motion event that started the fling. e2 The
* move motion event that triggered the current onFling.
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (e1.getX() - e2.getX() > FLIP_DISTANCE) {
Log.d(TAG, "Slide left...");
return true;
}
if (e2.getX() - e1.getX() > FLIP_DISTANCE) {
Log.d(TAG, "Slide right...");
return true;
}
if (e1.getY() - e2.getY() > FLIP_DISTANCE) {
Log.d(TAG, "Slide up...");
return true;
}
if (e2.getY() - e1.getY() > FLIP_DISTANCE) {
Log.d(TAG, "Slide down...");
return true;
}
Log.d(TAG, e2.getX() + " " + e2.getY());
return false;
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
//Log.d(TAG, "===> MainActivity call dispatchTouchEvent()");
//Log.d(TAG, "===> super.dispatchTouchEvent() default return true");
//Log.d(TAG, "--------------------------------------------------");
return super.dispatchTouchEvent(ev);
}
@Override
public void onUserInteraction() {
//Log.d(TAG, "===> MainActivity call onUserInteraction()");
//Log.d(TAG, "--------------------------------------------------");
super.onUserInteraction();
}
float Finger_0_DownX = 0;
float Finger_0_DownY = 0;
float Finger_1_DownX = 0;
float Finger_1_DownY = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int mActivePointerId =0;
int idx = event.findPointerIndex(mActivePointerId);
if (idx >=0 ) {
Finger_0_DownX = event.getX(idx);
Finger_0_DownY = event.getY(idx);
mRender.setFingerDown(0, Finger_0_DownX, Finger_0_DownY);
}
break;
case MotionEvent.ACTION_UP:
Finger_0_DownX = 0.0f;
Finger_0_DownY = 0.0f;
mRender.setFingerUp(0);
break;
default:
break;
}
switch(event.getActionMasked()) {
case MotionEvent.ACTION_POINTER_DOWN:
int mActivePointerId = 1;
int idx = event.findPointerIndex(mActivePointerId);
if (idx >=0 ) {
Finger_1_DownX = event.getX(idx);
Finger_1_DownY = event.getY(idx);
mRender.setFingerDown(1, Finger_1_DownX, Finger_1_DownY);
}
break;
case MotionEvent.ACTION_POINTER_UP:
Finger_1_DownX = 0.0f;
Finger_1_DownY = 0.0f;
mRender.setFingerUp(1);
break;
default:
break;
}
if (Finger_0_DownX != 0.0f && Finger_0_DownY != 0.0f) {
int mActivePointerId =0;
int idx = event.findPointerIndex(mActivePointerId);
if (idx >=0 ) {
mRender.setFingerPosition(0, event.getX(idx), event.getY(idx));
}
}
if (Finger_1_DownX != 0.0f && Finger_1_DownY != 0.0f) {
int mActivePointerId = 1;
int idx = event.findPointerIndex(mActivePointerId);
if (idx >=0 ) {
mRender.setFingerPosition(1, event.getX(idx), event.getY(idx));
}
}
return mDetector.onTouchEvent(event);
}
///////////////////////////////////////////////////////////////////////////////////////////////
}
这是 activity 布局。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frameLayout3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/fullscreenBackgroundColor"
android:theme="@style/ThemeOverlay.GraphicsDebugger.FullscreenContainer"
tools:context=".DemoFullscreenActivity">
<android.opengl.GLSurfaceView
android:id="@+id/gl_surface_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<com.example.graphicsdebugger.VKSurfaceView
android:id="@+id/vk_surface_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<CheckBox
android:id="@+id/ssao_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="SSAO"
app:layout_constraintBottom_toTopOf="@+id/sssss_check_box"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.019"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.728" />
<CheckBox
android:id="@+id/sssss_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="272dp"
android:text="SSSSS"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.019"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/textRadius"
android:layout_width="72dp"
android:layout_height="35dp"
android:text="Radius:5"
app:layout_constraintBottom_toBottomOf="@+id/gl_surface_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.175"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.101" />
<TextView
android:id="@+id/textCoefficient"
android:layout_width="111dp"
android:layout_height="35dp"
android:text="Coefficient:150"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.419"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.101" />
<TextView
android:id="@+id/textBias"
android:layout_width="72dp"
android:layout_height="35dp"
android:text="Bias:5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.68"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.101" />
<TextView
android:id="@+id/textKernelSize"
android:layout_width="111dp"
android:layout_height="35dp"
android:text="Kernel Size:16"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.925"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.101" />
<SeekBar
android:id="@+id/seekBarKernelSize"
android:layout_width="146dp"
android:layout_height="28dp"
android:max="8"
android:min="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.935"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.043" />
<SeekBar
android:id="@+id/seekBarCoefficient"
android:layout_width="146dp"
android:layout_height="28dp"
android:max="300"
android:min="100"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.408"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.041" />
<SeekBar
android:id="@+id/seekBarRadius"
android:layout_width="146dp"
android:layout_height="28dp"
android:max="100"
android:min="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/gl_surface_view"
app:layout_constraintHorizontal_bias="0.141"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.04" />
<SeekBar
android:id="@+id/seekBarBias"
android:layout_width="146dp"
android:layout_height="28dp"
android:max="30"
android:min="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/gl_surface_view"
app:layout_constraintHorizontal_bias="0.675"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.041" />
</androidx.constraintlayout.widget.ConstraintLayout>
这是AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.graphicsdebugger">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.GraphicsDebugger">
<activity android:name=".RendererSettingsActivity"></activity>
<activity
android:name=".DemoFullscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/title_activity_demo_fullscreen"
android:theme="@style/Theme.GraphicsDebugger.Fullscreen"
android:launchMode="singleInstance"/>
<activity android:name=".RenderingEngineActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
在 AndroidManifest.xml 的 <activity>
标签中,添加行 android:screenOrientation="portrait"
.
参考https://www.geeksforgeeks.org/designing-the-landscape-and-portrait-mode-of-application-in-android/添加横向布局。布局文件将位于 res/layout-land/ 目录。布局 xml 文件与 res/layout 目录中的文件同名。该文件名将在 setContentView(R.layout.activity_layout_name) 中使用。 activity 的 landsacpe/portrait 布局选择在 AndroidManifest.xml 参数 android:screenOrientation="value" 中设置,作为实验值,而值要么是横向的,要么是纵向的。当我们在AndroidManifest.xml中选择纵向模式时,对应的activity会在res/layout目录下找到布局文件,并设置ContentView。选择景观时,它将在res/layout-land目录中找到布局文件。所以在res/layout和res/layout-land目录下,layout文件名应该是一样的,因为我们在activity里调用了setContentViewAPI,参数应该都适合res/layout 和 res/layout-land 目录中的文件。
我需要在横向布局中设置我的 activity,因此在 AndroidManifest.xml 对应的 activity 中,我设置 android:screenOrientation="横向"。
然后 Activity 代码将 setContentView 使用 res/layout-land 目录中的布局文件。在横向布局 xml 文件中,我有两个视图,一个是 GLSurfaceView,另一个是 VKSurfaceView。