通过数据绑定从 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,您应该使用不同的方法:
- 用 activity 实例化 ViewModelProvider。 (ViewModel 将在 activity 内的所有片段之间共享)
- 用 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
0。问题
我能够实现另一个问题中看到的数据绑定(
希望有人能帮助我。
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,您应该使用不同的方法:
- 用 activity 实例化 ViewModelProvider。 (ViewModel 将在 activity 内的所有片段之间共享)
- 用 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