ViewPager is not working correctly after device rotation - android

After rotation, one old page is displayed, followed by new pages.
Before rotation 1.
After rotation 2.
Layout with ViewPager:
<RelativeLayout ...
<androidx.viewpager.widget.ViewPager
android:id="#+id/pager"
android:overScrollMode="never"
android:layout_marginStart="16dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="10dp"
android:layout_height="match_parent"
android:layout_width="match_parent">
</RelativeLayout>
Fragment with this layout:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = inflater.inflate(layoutId(), container, false)
view.findViewById<ViewPager>(R.id.pager).adapter = TextPagerAdapter(activity!!.supportFragmentManager, listOf())
return view
}
TextPagerAdapter:
override fun getItem(position: Int): Fragment = PageFragment.newInstance("sssssss ssss $position")
override fun getCount() = 5//pageText.size
}
PageFragment:
override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {
val view = inflater.inflate(layoutId(), container, false)
view.findViewById<TextView>(R.id.page_content_textView).text = arguments!!.getCharSequence(PAGE_TEXT)
return view
}

I forgot to check if the content fragment is already created.
The solution is to check if the savedInstanceState == null. And create new fragment if that condition is true.
In MyActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState == null) this.supportFragmentManager.beginTransaction()
.add(containerViewId, CollectionDemoFragment()).commit()
}

Related

cant get any component in fragment class (kotlin)

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

Fragment incide AppCompatDialog

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?

Kotlin doOnLayout not setting visibility.GONE

I have a custom ConstraintLayout Myword. when I set the visibility of myword1 to GONE inside kotlin fun doOnLayout, it becomes invisible but myword2 doesn't move down.
But if I set its visibility to GONE in XML or outside doOnLayout, it works as intended.
<learnprogramming.academy.relaf.Myword
android:id="#+id/myword1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<learnprogramming.academy.relaf.Myword
android:id="#+id/myword2"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#id/myword1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
Source code:
lateinit var bannerword : MutableList<Myword>
lateinit var swippon : ConstraintLayout
fun updatewords{
swippon.doOnLayout {
if (swippon.height>1000) bannerword[0].visibility = View.GONE}
class PhrasesFragment: Fragment() {
companion object {
fun newInstance(): PhrasesFragment {
return PhrasesFragment()
}
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.inglesa_screen, container, false) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bannerword=mutableListOf(myword1,myword2)
swippon=parent
updatewords()
}
}
doOnLayout function when layout is laid out calculates parent Layout height and eventually removes myword1. I actually solved changing doOnLayout with Handler(Looper.getMainLooper()).post{} but is wrong with doOnLayout? How should i have used it in the correct way?

Android Buttons in Fragments to not get triggered

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 ->
}
}

Fragments inside other fragment: crash with "has not been attached yet."

Hi I have a strange problem. MainActivity has a framelayout and a main fragment EnterFragment.
EnterFragment has a framelayout and i'd like to see other 2 fragments. SignupFragment and LoginFragment.
When EnterFragment starts, it shows SignupFragment.java.. after MainActivity invoke a method of EnterFragment to change fragment to LoginFragment but app crash:
java.lang.IllegalStateException: Fragment EnterFragment{95bc7de (70f980b2-eff8-4e4c-a644-e95544b73584)} has not been attached yet.
at androidx.fragment.app.Fragment.getChildFragmentManager(Fragment.java:923)
Here the project: https://www.dropbox.com/s/qq1kl4qw688ipjr/example.zip?dl=0
Here the code:
//MainActivity
class MainActivity : AppCompatActivity() {
private var enterFragment: EnterFragment?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showEnter()
}
private fun showEnter() {
enterFragment= EnterFragment.newInstance()
this.replaceFragmentTransition(R.id.fragmentContainer, EnterFragment.newInstance(), EnterFragment.TAG )
var handler= Handler()
handler.postDelayed(Runnable {gotoLoginFromSignup() }, 8000)
}
private fun gotoLoginFromSignup() {
enterFragment?.gotoLogin()
}
}
//EnterFragment
class EnterFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_enrer, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
this.replaceFragmentTransition(R.id.fmContainer, SignuFragment.newInstance(), SignuFragment.TAG )
}
fun gotoLogin(){
this.replaceFragmentTransition(R.id.fmContainer, LoginFragment.newInstance(), SignuFragment.TAG )
}
companion object {
val TAG: String="EnterFragment"
#JvmStatic
fun newInstance() = EnterFragment()
}
}
//SignupFragment
class SignuFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_signup, container, false)
}
companion object {
val TAG: String="SignuFragment"
#JvmStatic
fun newInstance() = SignuFragment()
}
}
//LoginFragment
class LoginFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_login, container, false)
}
companion object {
val TAG: String="LoginFragment"
#JvmStatic
fun newInstance() = LoginFragment()
}
}
//EXTENSIONS
fun FragmentActivity.replaceFragmentTransition(
container: Int,
fragment: Fragment?,
tag: String
) {
fragment?.let {
var transition = this.supportFragmentManager
.beginTransaction()
transition.replace(container, it, tag)
.commitNowAllowingStateLoss()
}
}
fun Fragment.replaceFragmentTransition(
container: Int,
fragment: Fragment?,
tag: String
) {
fragment?.let {
var transition = this.childFragmentManager
.beginTransaction()
transition.replace(container, it, tag)
.commitNowAllowingStateLoss()
}
}
//main activity layout
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragmentContainer"
android:layout_width="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_height="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
//enterFragment
<androidx.constraintlayout.widget.ConstraintLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".EnterFragment">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fmContainer"
android:layout_width="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_height="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
Replace this
this.replaceFragment(R.id.fragmentContainer, FatherFragment.newInstance(), FatherFragment.TAG )
with
this.replaceFragment(R.id.fragmentContainer, fatherFragment!!, FatherFragment.TAG )
while transaction, you are passing different instance & calling openLogin() with another instance.
FatherFragment.newInstance() will give new instance.

Categories

Resources