与DialogX一起完结全屏WebView对话框和沉溺式适配

开发中咱们往往会遇到一种需求,需求临时弹出一个 Web 层展现 H5 页面,iOS 端供给了一种原界面下沉的全屏打开 WebView 能够很便利的完结,用户也能够通过下滑操作封闭 Web 页面的阅读返回原界面。

要在 Android 渠道完结类似的作用,能够尝试运用 DialogX 的 FullScreenDialog 调配 WebView 完结沉溺式的全屏阅读器出现,同样的,也支撑滑动到 Web 页面顶端时继续向下滑动封闭对话框的操作,别的也支撑沉溺式哦,跟随我一起来看看我是怎么完结这样炫酷的功用吧!

与DialogX一起实现全屏WebView对话框和沉浸式适配

首要介绍一下 DialogX

DialogX 是一款简单易用的对话框组件,相比原生对话框运用体验更佳,可自定义程度更高,扩展性更强,轻松完结各种对话框、菜单和提示作用,更有iOS、MIUI、Material You等主题扩展可选。

能够移步之前的文章查看详细介绍:运用 DialogX 快速构建 Android App 对话框 – ()

先来一起创建一个全屏 WebView 对话框吧!

如上图所示,是一个从屏幕下方打开的全屏对话框,它根据 DialogX 的 FullScreenDialog 完结,只需求自定义一个 WebView 布局即可,要完结滑动承继,需求自定义 WebView 并完结一个 DialogX 的接口,范例代码如下所示:

public class CustomWebView extends WebView implements ScrollController {
  public CustomWebView(@NonNull Context context) {
    super(context);
   }
  
  public CustomWebView(@NonNull Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
   }
  
  public CustomWebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
   }
  
  @Override
  @Deprecated
  public boolean isLockScroll() {
    return lockScroll;
   }
  
  boolean lockScroll;
  
  @Override
  public void lockScroll(boolean lockScroll) {
    this.lockScroll = lockScroll;
   }
  
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (lockScroll) return false;
    return super.onTouchEvent(event);
   }
  
  @Override
  public int getScrollDistance() {
    return getScrollY();
   }
  
  boolean canScroll = true;
  
  public CustomWebView setCanScroll(boolean canScroll) {
    this.canScroll = canScroll;
    return this;
   }
  
  @Override
  public boolean isCanScroll() {
    return canScroll;
   }
}

按照上述固定写法即可。

将 CustomWebView 增加一份布局,放上封闭按钮即可完结界面布局的搭建作业。为便利后续操作,暂时将布局命名为 layout_dialog_webview 参考布局代码如下,请注意设置 tag 为 ScrollController 以便利 FullScreenDialog 绑定滑动承继组件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">
​
  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:orientation="horizontal">
​
    <Space
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_weight="1" />
​
    <TextView
      android:id="@+id/btn_close"
      android:layout_width="wrap_content"
      android:layout_height="match_parent"
      android:gravity="center"
      android:paddingLeft="15dp"
      android:paddingRight="15dp"
      android:text="封闭"
      android:textColor="@color/dialogxIOSBlue"
      android:textSize="18dp" />
​
  </LinearLayout>
​
  <com.kongzue.dialogxdemo.CustomWebView
    android:id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="ScrollController" />
</LinearLayout>

接下来编写 FullScreenDialog 的完结代码

FullScreenDialog.show(new OnBindView<FullScreenDialog>(R.layout.layout_dialog_webview) {
      private TextView btnClose;
      private CustomWebView webView;
      @Override
      public void onBind(FullScreenDialog dialog, View v) {
        btnClose = v.findViewById(R.id.btn_close);
        webView = v.findViewById(R.id.webView);
        //Set WebView Settings...
        webView.loadUrl("https://www.example.com");
       }
     });

即可发动一个全屏展现的 WebView 对话框并加载一个页面。

那么该怎么完结沉溺式适配呢?FullScreenDialog 默认情况下已经做好了一些沉溺式作业,例如对话框的内容一定会在沉溺式的“安全区”范围内,对话框顶部只会上移到手机状态栏以下,而对话框内容底部也会在导航栏以上,但这间隔咱们想要的页面内容“下沉”到导航栏以下的需求不符,此刻只需求一个开关即可完结:

.setBottomNonSafetyAreaBySelf(true)

此设置是 FullScreenDialog 的设置,假如没有请更新至最新测试版别的 DialogX,开启后内容布局将被答应下沉到底部导航栏以后显示,此刻 Web 页面将能够沉溺的显示在导航栏后了,那么接下来的问题就是怎么为页面内容设置一个 paddingBottom,使其内容不分能够在用户可操作的屏幕安全区内,沉溺,但不影响正常运用。

设置页面内容到安全范围内

常见的计划大致是对内容直接设置一个导航栏高度的 paddingBottom,使其背景不受躲藏但内容在安全范围内,

我之前 有一篇文章 有说过沉溺式的基本逻辑在于正确的对安全区和非安全区的处理,准则即:将背景下沉,将操作区域和主要内容区域放在安全区内:

与DialogX一起实现全屏WebView对话框和沉浸式适配

要完结这点,咱们需求获取底部导航栏的高度,再对 WebView 的页面内容进行 paddingBottom 的设置,前者其实 DialogX 已经帮你处理好了,只需求一句代码即可获取:

int bottomUnsafeAreaHeight = dialog.getDialogImpl().boxRoot.getUnsafePlace().bottom;

但实践上,不主张这样粗犷的获取,由于非安全区位置或许由于横竖屏切换,以及不分设备上能够躲藏导航栏导致高度发生变化,更主张的计划是动态回调的方式获取,这样愈加安全可靠:

dialog.getDialogImpl().boxRoot.setOnSafeInsetsChangeListener(new OnSafeInsetsChangeListener() {
  @Override
  public void onChange(Rect unsafeRect) {
    int bottomUnsafeAreaHeight = unsafeRect.bottom;
   }
});

bottomUnsafeAreaHeight 的值就是底部非安全区的高度啦,单位是像素。

但此刻你又会遇到一个严重问题,那就是 WebView 不吃 setPadding 这套,对 WebView 设置 padding 是无效的,咱们需求使页面内容 paddingBottom = bottomUnsafeAreaHeight 的间隔以保证当 WebView 滑动到底部后为导航栏空出一段间隔。

那么此刻就得用到 WebView 的 Client,在其中 onPageFinished 方法设置一段 js 来为页面的 body 设置一段底部 padding 来达到需求的作用,不废话直接上代码:

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
      if (unsafeRect != null) {
      webView.loadUrl("javascript:document.body.style.paddingBottom="" + px2dip(bottomUnsafeAreaHeight) + "px"; void 0");
     }
        super.onPageFinished(view, url);
   }
}

其中,px2dip 是一个像素对 dp 的转化东西,由于适配移动端的 H5 在 WebView 出现时默认会习惯屏幕的像素密度,因而关于网页内容中的 px 实践上等同于 dp 的值,因而此处需求将底部非安全区的高度转化为 dp 当做 px 设置给页面。

上述代码为页面的 body 增加了 paddingBottom 的设置,但这需求 H5 页面支撑,假如你需求显示的 H5 页面不收效,请依据实践需求查看内部元素适当的调整上述 js 以适配实践需求。

至此,根据 DialogX 的 FullScreenDialog 完结全屏 WebView 和沉溺式适配作业也就基本完结了,让咱们在 App 悉数沉溺式的道路上更进一步吧!