I'm trying to access a WebView from a Fragment and kotlin keeps on saying:
kotlin.TypeCastException: null cannot be cast to non-null type android.webkit.WebView
I have tried to make it null as default then init it but that does not work either. Any suggestions on how I can make it work?
My code:
private lateinit var webView: WebView
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater!!.inflate(R.layout.editor_edit_fragment, container, false)
webView = view.findViewById(R.id.webview) as WebView
resumeWebView()
return view
}
xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/webview" />
</LinearLayout>
You need to run onCreateView first, then onViewCreated to set up WebView.
class FragmentWebview : Fragment() {
lateinit var contentView: View
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
contentView = inflater.inflate(R.layout.fragment_fragment_webview, container, false)
return contentView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val webview = contentView.findViewById<WebView>(R.id.myWebview)
val url = "http://google.com"
val webSettings = myWebview.settings
webSettings.javaScriptEnabled = true
webSettings.domStorageEnabled = true
webview.webViewClient = WebViewClient()
webview.loadUrl(url)
}
}
Related
i manually created a fragment. but cant declare a component like web view or button. when i paste and edit "val webview: WebView ..." there is error "Fragment(R.layout.fragment_htmlviewer)" too. i dont know how to do, when i create from android studio, it looks like very complicated. so i watched a video and this is more easy but cant declare components. im very beginner so help me please... my code:
fragment_htmlviewer.xml
<WebView
android:id="#+id/htmlViewer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floating_action_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="#string/fabdescription"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="#drawable/ic_left_arrow_icon" />
HtmlViewerFragment.kt
class HtmlViewerFragment : Fragment(R.layout.fragment_htmlviewer) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val webview: WebView = getView()!!.findViewById<View>(R.id.htmlViewer) as WebView
}
}
I recommend you to use the binding structure, it is a more preferred structure today.
build.gradle(module)
buildFeatures {
viewBinding true
dataBinding true
}
HtmlViewerFragment
private var _binding: FragmentHtmlViewerBinding? = null
private val binding
get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentHtmlViewerBinding.inflate(inflater, container, false)
//.. this is write code
binding.apply{
//eg:
htmlViewer.setOnClickListener{
}
}
return binding.root
}
override fun onStart() {
super.onStart()
htmlViewer = requireView().findViewById(R.id.htmlViewer) as WebView
htmlViewer!!.loadUrl("https://www.google.com")
}
this is solution.
htmlViewer = requireView().findViewById(R.id.htmlViewer) as WebView
fixed
Here is the kotlin file of the fragment:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? ): View? {
val view = inflater.inflate(R.layout.fragment_blank, container, false)
view.textView1 <- Here is the problem
return view
}
Down here is xml file of the fragment. I hope it's all right...
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/purple_200"
tools:context=".BlankFragment">
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="1"
android:gravity="center"
android:textSize="80sp" />
</FrameLayout>
textView = findViewById(R.id.yourId);
and next you can use it
Actually findViewById() is not available on the Fragment class.
However, you can use inflated view to access the findViewById() as shown on this example.
class MyFragment : Fragment() {
lateinit var textView: TextView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_my, container, false)
//use view to access findViewById() method
textView = view.findViewById(R.id.textView1)
textView.text = "Test 1"
return view
}
}
That said the recommended way would be to use Databinding or View Binding
I have simple DialogWindow
XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="150dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<fragment
android:id="#+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation"/>
</LinearLayout>
Code:
class DialogWindowBuyingStock(context: Context, private val viewModel: MainViewModel, private val stock: Stock) : AppCompatDialog(context) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.buy_stock_dialogwindow)
}
}
In which i have some fragments for example the Main one:
class MainFragment : Fragment() {
private var _binding: MainFragmentBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val homeViewModel =
ViewModelProvider(this)[MainFragmentViewModel::class.java]
_binding = MainFragmentBinding.inflate(inflater, container, false)
val root: View = binding.root
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
main_buy_button.setOnClickListener {
Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_buyFragment)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
It works perfectly for the first time i start Dialog Window, but when i close it and start again, i got this llegalArgumentException: Binary XML file line #20: Duplicate id 0x7f080136, tag null, or parent id 0xffffffff with another fragment for androidx.navigation.fragment.NavHostFragment
How can i fix that?
I'm trying to use Data binding to run a function when an onClick event occurs, I'm hoping someone can tell me what I'm doing wrong here.
The log item in myClick doesn't run.
XML
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="myBinding"
type="com.example.deletebindingtest.MyFragment" />
</data>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyFragment"
android:orientation="vertical">
<Button
android:id="#+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/button"
android:onClick="#{(view) -> myBinding.myClick()}"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</layout>
My Fragment
class MyFragment : Fragment() {
private lateinit var binding: FragmentMyBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Inflate view and obtain an instance of the binding class
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_my,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
}
fun myClick() {
Log.i("TEST", "Its working")
}
}
When I click on the extension in the XML it takes me to myClick function.
a Quick fix is on onCreateView add binding.myBinding=this
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Inflate view and obtain an instance of the binding class
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_my,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
binding.myBinding=this // here
return binding.root
}
also I prefer listener binding you can check it here
Why do buttons in Fragments to not get triggered? I've already spent about 5 hours on this, but no onClick / onFocusListener will trigger
Edit: Code
So this Fragment(s) is on a ViewPager2 on my MainActivity and
it just wont trigger any Callback Methods. I have also tried to but those onClick initializations everywhere
Fragment:
class SearchFragment : Fragment() {
private lateinit var searchBinding: FragmentSearchBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
searchBinding = FragmentSearchBinding.inflate(layoutInflater)
interface OnSearch {
fun onArticleSelected(position: Int)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_search, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var test = activity?.findViewById<TabLayout>(R.id.tab_layout)
searchBinding.searchBar.setOnFocusChangeListener{view, hasFocus ->
if (hasFocus){
if (test != null) {
test.isVisible = false
}
Log.d("SearchFragment", "onFocus")
}else{
if (test != null) {
test.isVisible = true
}
}
}
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.search.SearchFragment"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.button.MaterialButton
android:id="#+id/testButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="#+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:hint="Search"
android:focusedByDefault="true"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/searchRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</FrameLayout>
Try something like this
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) {
super.onCreateView(view, savedInstanceState)
val binding = FragmentSearchBinding.inflate(inflater, container, false);
val view = binding.root
// Set binding
return view;
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById(R.id.searchBar).setOnFocusChangeListener { view, hasFocus ->
}
}