I have activity in which added two fragments. when i am clicking on top fragment the views from previous fragment get focus. I should have the previous fragment in backstack for some other purpose. how to clear focus from previous fragment?
Set clickable of your current layout to true
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true" />
Fragment over another fragment issue
Related
I have a main activity that launches a fragment through a fragment transaction. I want the fragment to completely fill the screen, showing no views at all from the parent. However, when I commit the fragment transaction I can still see the bottom nav view of the parent activity as well as it's buttons. I made a little demo app to show what I mean:
The main activity has a yellow background. The "Testclick" button starts a fragment transaction using the code below.
This is the result of the transaction. The red background of the fragment is now visible, but the bottomNavigationView and Buttons remain visible (Which is not desired).
Fragment Transaction
bttn.setOnClickListener {
supportFragmentManager
.beginTransaction()
.replace(R.id.contentview, Frag1())
.addToBackStack(null)
.commit()
}
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:id="#+id/contentview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/yellow"
tools:context=".MainActivity">
...
</androidx.constraintlayout.widget.ConstraintLayout>
Your R.id.contentview must be in the background behind the buttons
Ah actually you know what there is a good tool, called LayoutInspector in Tools -> Layout inspector, you can actually see how the layout is set up while your activity is running. In your case the layout of fragment is added inside the layout of activity.
Sorry didnt see the id at first
My App uses a single activity architecture which has a NestedScrollView in the activity layout
<LinearLayout 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:id="#+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.navigationadvancedsample.MainActivity">
<androidx.core.widget.NestedScrollView
android:id="#+id/app_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true">
<FrameLayout
android:id="#+id/nav_host_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/bottom_nav"/>
</LinearLayout>
My issue is that that when I scroll a fragment, then navigate to another, then go back, the scroll position is reset. I've seen another answer which stated that adding IDs to the layouts should fix the issue, but it hasn't for me. Also, interestingly, the scroll position saves fine on configuration change.
I'm using NavigationComponents, could this be related? Here's a sample project that reproduces the issue (based on Google's NavigationAdvancedSample)
NestedScrollView has wrapped the Navigation Container in the activity_main layout. So it is the activity that saves the scroll state. There are 3 fragments. Home fragment has fixed height, Leaderboard and Register fragments are scrolling. When you scroll in the Leaderboard or Register and switch to the other one the scroll state does not change(since both can scroll to roughly the same height) but if you switch to home fragment scroll state resets because it has fixed height(size of the screen). Replacing NestedScrollView with the ScrollView didn't change anything as I examined it.
I think the right design is to wrap each fragment with NestedScrollView and set and get scroll state for each fragment.
Navigation component does not add the fragment to the activity state but replace it. So fragments get recreated after by switching between them. So you see scroll state is being reset. You can check it yourself by putting some log in the onCreateView of first fragment and see the log appears twice.
The attached picture shows a ViewPager with 3 pages. Each page is implemented as a Fragment. The Toolbar has a + icon in black for adding a new patient. When the + icon is pressed, a nested fragment should be created inside the Patients page which allows the creation of a new patient.
In the Logcat, I can see that the fragment lifecycle callbacks for the nested fragment are called right upto onResume(), but the view for the nested fragment is not rendered.
I am doing this to create the nested fragment and insert it into the parent fragment view hierarchy:
FrPatientDetails frChild = new FrPatientDetails();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction()
.replace(R.id.flPatientsPage, frChild);
transaction.addToBackStack(null)
.commit();
R.id.flPatientsPage is a FrameLayout in the Patients page into which I am trying to insert the nested fragment.
I am getting a feeling that the way to insert a child fragment into a parent fragment hosted in a ViewPager might be different, but I am not clear what to do.
Would someone be able to help here.
Update: Added the xml for the Patients page (parent)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/patients_page_linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/lvHomeViewPatientsPage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#color/colorPrimary"
android:dividerHeight="1dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp"
android:textColor="#android:color/black" />
<TextView
android:id="#+id/tvEmpty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textColor="#android:color/black"
android:text="#string/patients_page_empty"
android:fontFamily="sans-serif"
android:gravity="center"
android:textSize="16sp"
/>
<FrameLayout
android:id="#+id/flPatientsPage"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Update: This is the screenshot after following what #Filo suggested:
To summarize, here is the problem that I was facing:
There is an Activity A containing a TabLayout and ViewPager(V). V contains 3 pages (fragments). One of the fragments(F1) contains a child fragment C. I was able to display F1. I was unable to display C when the user clicked a button in F1.
Solution: V used a FragmentPagerAdapter to setup the fragments. Inside FragmentPagerAdapter.getItem(), do not launch F1 directly. Instead, launch a a fragment called F1Wrapper which contains a FrameLayout. Inside F1Wrapper.onCreateView(), create a FragmentTransaction adding F1 to the backstack. Use getChildFragmentManager to create the transaction. Pass the FrameLayout of F1Wrapper as the view container for F1.
When the user clicks the button in F1 to launch fragment C, create a FragmentTransaction.replace() in F1Wrapper which adds C to the backstack. Use getChildFragmentManager to create the transaction. Again, pass the FrameLayout of F1Wrapper as the view container for C. C will now replace F1 in the backstack and will be displayed.
Note: You cannot pass the ViewPager as the view container for C. That is the crux of the problem and the main reason why we need to use a wrapper fragment. If you pass V as the view container for C, C.onCreateView() will crash.
I have an activity A with a fragment A inside.
Activity A uses layout X, and fragment A uses layout A.
code of layout X:
<RelativeLayout 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=".MainActivity" >
<fragment
android:id="#+id/fragment1"
android:name="android.app.DialogFragment"
android:layout_width="wrap_content"
android:layout_height="500dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="113dp"
class="com.example.fragtester.FragA" />
</RelativeLayout>
Layout A is just textview + linearlayout.
I set up another fragment B that uses layout B.
Now that I use the following code in activity A to change the fragments:
Fragment f = new FragB();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment1, f);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
I end up having layout B displaying under layout A.
So I use a FrameLayout to wrap the fragment in layout X and use
ft.replace(R.id.FrameLayout1, f);
Now the view is working nicely. Though, another problem arises.
Although layout B covers layout A, but the buttons are still active.
That means when I am viewing layout B, I can still click buttons on layout A, even if I am not seeing it.
And even when I add fragment C/D/E..... (layouts C/D/E....), the buttons on layout A is still active.
Can anybody explain why is that? Am I using fragments wrongly? Thanks!
A way to get through is to make layout A blank, and use other layout to cover it. But it doesn't seems to be the "right" way??
Remove the fragment and add a FrameLayout
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff" >
</FrameLayout>
then add fragments programmatically.
In android fragment button click pass through the fragments (i dont know if the fragments are suppose to work like that). what I used to do in such a situation is to make the layout of the fragment clickable. so the clicks wont pass through.
Instead of having fragment in your xml, try to create empty container for a fragments. For example empty frame layout. And then programmatically put your fragments in there.
Add the following attribute to the XML root layout of the fragment that goes on top.
android:clickable="true"
This will ensure that touch events will not propagate further than the top layer.
I read some questions like it, but I dont understand well what should I do in my hiearchy?
I have
<fragment
android:id="#+id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
class="com.****.****.ui.TabsFragment" />
for tab menu on bottom of screen
and
<FrameLayout
android:id="#+id/details"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/tickerLL"
android:layout_below="#id/header"
android:background="#drawable/background" />
for other will created fragments.
I have 9 tab menus, everyone is a fragment.
Some fragments's landscape are another activity. And I rotate back phone, fragments are working well. But if I rotate fast after and after, My fragment Activty, TabsFragment and and other created fragments are recreated and my fragments are overlapping.
I manage my fragments in TabsFragment. And they works dynamicly, my abstract fragment class, has a previous fragment and subfragment. When I press back, previous fragment closes its subfragment and null it.
What should I do?
During a configuration change, Android restores or recreates all fragments that the old activity had when setting up the new activity. Hence, you need to take that into account when working with the new activity instance -- do not assume that you are starting with a clean slate.