[英]Android custom SurfaceView orientation can't rotate from portrait to landscape
我是一名新的android應用工程師。 我正在嘗試制作一個 vulkan 渲染后端演示,它使用 SurfaceView 作為 android Java 代碼上的視圖。 我也使用 GLSurfaceView 制作了 gles 渲染后端演示。 在應用程序代碼中,我使用 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) API 將活動從默認縱向設置為橫向。 但是它在 GLSurfaceView 上工作時在 SurfaceView 上不起作用。
我使用 renderdoc 捕獲渲染結果,圖像是橫向布局(與 gles 后端相同的布局)。 我懷疑活動或 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);
}
///////////////////////////////////////////////////////////////////////////////////////////////
}
這是活動布局。
<?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 的標簽中,添加行 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 的橫向/縱向布局的選擇在 AndroidManifest.xml 參數 android:screenOrientation="value" 中設置,而值是橫向或縱向。 當我們在AndroidManifest.xml中選擇豎屏模式時,對應的activity會在res/layout目錄下找到layout文件並setContentView。 選擇景觀時,它將在Res/Layout-Land目錄中找到布局文件。 這就是為什么 res/layout 和 res/layout-land 目錄下,layout文件名應該是一樣的,因為我們在activity中調用setContentView API,這個參數應該同時適合res/layout和res/layout-中的文件土地目錄。
我需要在橫向布局中設置我的活動,所以在 AndroidManifest.xml 對應的活動中,我設置了 android:screenOrientation="landscape"。
然后 Activity 代碼將 setContentView 使用 res/layout-land 目錄中的布局文件。 在橫向布局 xml 文件中,我有兩個 View,一個是 GLSurfaceView,另一個是 VKSurfaceView。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.