通过数据绑定从 BottomSheetDialogFragment 中的按钮单击在 WebView 中加载 URL

Loading URL in WebView from Button Click in BottomSheetDialogFragment via Data-Binding

0。问题

的问题给了我实现数据绑定库的想法,目的是在单击底部的按钮时在 Webview 片段中打开 Link Sheet 片段.

我能够实现另一个问题中看到的数据绑定(,但是当在所述底部单击按钮时 WebView 不会加载新的 URL Sheet Fragment. 我从控制台得到反馈,按钮被点击并且 LiveData 被改变了。 所以,我认为 WebView 会在 LiveData 更改时自动重新加载,但似乎并非如此......所以我没有看到我的错误并且不确定我是否正确实施了所有内容。

希望有人能帮助我。


1。分别类

1.1。 WebViewFragment

    class WebviewFragment : Fragment() {

    private lateinit var webView: WebView

    companion object {
        fun newInstance() = WebviewFragment()
    }

    private lateinit var viewModel: WebViewViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val binding: FragmentMainWebviewBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_main_webview, container, false)
        viewModel = ViewModelProvider(this).get(WebViewViewModel::class.java)

        binding.webViewModel = viewModel
        binding.lifecycleOwner = this
        return binding.root
    }

    @SuppressLint("SetJavaScriptEnabled", "JavascriptInterface")
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        webView = webViewMain
        webView.settings.javaScriptEnabled = true
    }
}

1.2。 WebViewModel

    class WebViewViewModel : ViewModel() {

    val webViewUrl = MutableLiveData<String>().apply{ value = "file:///android_asset/html_files/gallery_page.html" }

    companion object WebViewUrlLoader {
        @BindingAdapter("loadUrl")
        @JvmStatic
        fun  WebView.setUrl(url: String) {
            this.loadUrl(url)
        }
    }
}

1.3。 Web 视图布局 (XML)

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="webViewModel"
            type="com.example.ui.main.webview.WebViewViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/main_screen_webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainFragmentGalleryView"
        >
        <WebView
            android:id="@+id/webViewMain"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:loadUrl="@{webViewModel.webViewUrl}"
            android:paddingBottom="52dp" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

1.4。底部Sheet 片段

class BottomSheetFragment : BottomSheetDialogFragment() {

    private var fragmentView: View? = null
    private lateinit var viewModel: WebViewViewModel

    companion object {
        fun newInstance() = BottomSheetFragment()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        fragmentView = inflater.inflate(R.layout.view_modal_bottom_sheet, container, false)
        return fragmentView
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = ViewModelProvider(this).get(WebViewViewModel::class.java)
        initView()
    }

    override fun getTheme(): Int {
        return R.style.Theme_NoWiredStrapInNavigationBar
    }

    private val mBottomSheetBehaviorCallback: BottomSheetCallback = object : BottomSheetCallback() {
        var isBottomSheetUp = false
        override fun onSlide(bottomSheet: View, slideOffset: Float) {
            //TODO("Not yet implemented")
        }

        override fun onStateChanged(bottomSheet: View, newState: Int) {
            if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                isBottomSheetUp = false
                dismiss()
            } else isBottomSheetUp = true
        }

    }

    override fun setupDialog(dialog: Dialog, style: Int) {
        //super.setupDialog(dialog, style)
        val contentView =
            View.inflate(context,
                R.layout.view_modal_bottom_sheet, null)
        dialog.setContentView(contentView)
        val layoutParams =
            (contentView.parent as View).layoutParams as CoordinatorLayout.LayoutParams
        val behavior = layoutParams.behavior
        if (behavior != null && behavior is BottomSheetBehavior<*>) {
            behavior.setBottomSheetCallback(mBottomSheetBehaviorCallback)
        }
    }

    private fun initView() {

        action_my_pictures.setOnClickListener {
            viewModel.webViewUrl.value = "https://www.google.com/"
            Log.d("BottomSheet", "Button 1 Clicked ${viewModel.webViewUrl.value}")
        }
        action_favorites.setOnClickListener {
            viewModel.webViewUrl.value = "https://www.hotmail.de/"
            Log.d("BottomSheet", "Button 2 Clicked ${viewModel.webViewUrl.value}")

        }
        action_ranking.setOnClickListener {
            viewModel.webViewUrl.value = "https://amazon.com/"
            Log.d("BottomSheet", "Button 3 Clicked ${viewModel.webViewUrl.value}")

        }
        action_hall_of_fame.setOnClickListener {
            viewModel.webViewUrl.value = "https://m.daum.net/"
            Log.d("BottomSheet", "Button 4 Clicked ${viewModel.webViewUrl.value}")

        }
        action_liked_pictures.setOnClickListener {
            viewModel.webViewUrl.value = "https://m.nate.com/"
            Log.d("BottomSheet", "Button 5 Clicked ${viewModel.webViewUrl.value}")

        }
        action_events.setOnClickListener {
            viewModel.webViewUrl.value = "https://www.danawa.com/"
            Log.d("BottomSheet", "Button 6 Clicked ${viewModel.webViewUrl.value}")

        }
        action_close_bottom_sheet.setOnClickListener {
            dismiss()
        }
    }
}

1.5。底部Sheet布局(XML)

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="webViewModel"
            type="com.example.ui.main.webview.WebViewViewModel" />
    </data>


    <LinearLayout
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/bottomNavigationViewBackground"
        android:orientation="vertical"
        app:behavior_hideable="true"
        app:behavior_peekHeight="auto"
        app:layout_behavior="@string/bottom_sheet_behavior"
        app:behavior_fitToContents="true">


[7 Image/Icons as Buttons]
 Example:
            <LinearLayout
                android:id="@+id/action_my_pictures"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_weight="1"
                android:orientation="vertical"
                android:clickable="true"
                android:focusable="true">

                <ImageView
                    android:id="@+id/icon_my_pictures"
                    android:layout_width="36dp"
                    android:layout_height="36dp"
                    android:layout_gravity="center_horizontal"
                    android:src="@drawable/ic_user_color" />

                <TextView
                    android:id="@+id/icon_my_pictures_text"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_horizontal"
                    android:singleLine="true"
                    android:text="My Gallery"
                    android:paddingTop="6dp"
                    android:textAlignment="center"
                    android:textSize="12sp" />
        </LinearLayout>
    </LinearLayout>
</layout>

2。日志输出(针对按钮点击)

D/BottomSheet: Button 1 Clicked https://www.google.com/
D/BottomSheet: Button 2 Clicked https://www.hotmail.de/
D/BottomSheet: Button 3 Clicked https://amazon.com/
D/BottomSheet: Button 4 Clicked https://m.daum.net/
D/BottomSheet: Button 4 Clicked https://m.daum.net/
D/BottomSheet: Button 5 Clicked https://m.nate.com/
D/BottomSheet: Button 6 Clicked https://www.danawa.com/

非常感谢。

我认为问题出在您为 viewModel 提供的生命范围内。 目前您的代码如下所示:

viewModel = ViewModelProvider(this).get(WebViewViewModel::class.java)

此代码在两个不同的片段中调用,因为 ViewModelProvider 是使用片段的当前实例 (this) 初始化的。您的视图模型仅在此范围(片段范围)内可用。因此,在每个片段的末尾,您将获得新的 ViewModel。要在片段之间共享 ViewModel,您应该使用不同的方法:

  1. 用 activity 实例化 ViewModelProvider。 (ViewModel 将在 activity 内的所有片段之间共享)
  2. 用 parentFragment 实例化 ViewModelProvider。 (ViewModel 将在所有子片段之间共享)

示例:

viewModel = ViewModelProvider(requireActivity()).get(WebViewViewModel::class.java)

viewModel = ViewModelProvider(parentFragment).get(WebViewViewModel::class.java)

请同时检查:

How to scope ViewModels properly? https://developer.android.com/reference/android/arch/lifecycle/ViewModelProviders