Android端不旋转设备旋转WebView至横屏的实现与报错修复
问题原因
该崩溃由Android高版本API限制导致:从API 28(Android 9.0)开始,系统对Canvas裁剪操作做了严格限制,仅允许使用INTERSECT和DIFFERENCE两种Region.Op参数,你代码中调用clipRect时传入的Region.Op.REPLACE属于被禁用类型,直接触发IllegalArgumentException崩溃。
你参考的旧方案本身也存在固有缺陷:仅对绘制画布做了旋转处理,没有同步适配触摸事件坐标映射、视图宽高测量逻辑,即使绕过崩溃问题,也会出现触摸位置错位、页面内容拉伸变形、交互失效等问题。
正确实现方案
不需要重写draw方法手动操作Canvas,直接基于View原生旋转能力实现,全程无需修改Activity屏幕方向配置,设备保持竖屏状态即可让WebView单独横屏显示,兼容Android 9.0及以上版本。
1. 自定义支持横屏旋转的WebView
重写测量、布局、触摸事件相关方法,解决旋转后的尺寸适配、坐标映射问题:
import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.webkit.WebView; public class LandscapeWebView extends WebView { // 顺时针横屏传90,逆时针横屏传-90 private static final int LANDSCAPE_ROTATION = 90; public LandscapeWebView(Context context, AttributeSet attrs) { super(context, attrs); // 初始化时直接设置旋转角度 setRotation(LANDSCAPE_ROTATION); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 旋转后宽高互换,交换测量参数 super.onMeasure(heightMeasureSpec, widthMeasureSpec); // 回写互换后的测量尺寸 setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // 传递互换后的尺寸给父类 super.onSizeChanged(h, w, oldh, oldw); } @Override public boolean onTouchEvent(MotionEvent event) { // 转换触摸坐标,适配旋转后的视图坐标系 if (LANDSCAPE_ROTATION == 90) { event.setLocation(event.getY(), getWidth() - event.getX()); } else { event.setLocation(getHeight() - event.getY(), event.getX()); } return super.onTouchEvent(event); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 按旋转后的尺寸完成布局 super.onLayout(changed, l, t, l + getMeasuredWidth(), t + getMeasuredHeight()); } }
2. 布局文件配置
布局中WebView宽高直接匹配父容器即可,不要使用wrap_content避免测量异常:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.替换为你自己的包名.LandscapeWebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
3. Activity中初始化WebView
Activity不需要配置横屏属性,保持默认竖屏即可,按常规逻辑初始化WebView:
import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.webkit.WebSettings; import android.webkit.WebViewClient; public class WebViewActivity extends AppCompatActivity { private LandscapeWebView webView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_webview); webView = findViewById(R.id.webView); // 常规WebView配置 WebSettings settings = webView.getSettings(); settings.setJavaScriptEnabled(true); settings.setDomStorageEnabled(true); settings.setAllowFileAccess(true); webView.setWebViewClient(new WebViewClient()); // 加载目标页面 webView.loadUrl("你要加载的页面地址"); } @Override protected void onDestroy() { // 销毁WebView避免内存泄漏 if (webView != null) { webView.destroy(); } super.onDestroy(); } }
注意事项
- 如果需要切换横竖屏方向,只需要修改
LANDSCAPE_ROTATION的取值,触摸坐标转换逻辑已经做了适配 - 该方案支持WebView所有原生能力,包括视频全屏播放、表单输入、页面滚动、JS交互等,无需额外适配
- 如果WebView外层套了可滚动容器(比如ScrollView),需要把滚动容器也做同样的旋转适配,否则会出现滚动冲突
内容的提问来源于stack exchange,提问作者Poorvaja
相关产品推荐
相关产品推荐

