Fragment in LinearLayout not appear without layout_weight property - android

I have two fragments (MyListFragment, MyDetailFragment) in one activity(MyActivity). The first fragment is a list of items, the second one is detail of an item (which is another list, but I think it doesn't matter). The first list fragment is shown when MyActivity starts.
MyListFragment view:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment class="myapp.ActionsList"
android:id="#+id/actions_list_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
MyDetailFragment view:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="#android:id/list"
android:tag="#string/activities_list_tag"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
There is a click handler on MyListFragment which calls method in MyActivity which opens the MyDetailFragment.
#Override
public void onActionSelected(MAction action, Integer position){
/**some code...*/
getFragmentManager().beginTransaction()
.replace(R.id.fragment_container,
new MyDetailFragment(mAction,position)).commit();
}
The problem is:
that when I click on any item in MyListFragment, the MyDetailFragment won't show up (although I know it's lifecycle methods are called properly).
I found out that when I put android:layout_weight="1" to fragment definition in MyListFragment, it works. Does anybody know why?
As I understand the android:layout_weight property, it should play some role only when there are more view in LinearLaoyout, but I have only one.
This is the working layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment class="myapp.ActionsList"
android:id="#+id/actions_list_fragment"
**android:layout_weight="1"**
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Thanks

getFragmentManager().beginTransaction()
.replace(R.id.fragment_container,
new MyDetailFragment(mAction,position)).commit();
You are completely replacing a fragment, so there's only one fragment's view in fragment_container at a time. Better make fragment_container a FrameLayout and set height and width of fragment layout roots to match_parent.

You are using layout_weight wrong and i don't think u understood it's functionality. In order to function in LinearLayout parrent you must have a weightSum which will be the total weight of the layout. The second thing would be to set childs weight or height 0dp depending on the LinearLayout orientation. Every child of the layout must have a layout_weight and the total sum of the weight to be equal to weightSum. Such that the Layout will be splited automatically depending you're weight.

Ok, I was doing wrong one thing.
Only fragments loaded programmatically can be replaced. Not fragments defined in xml.
But I didn't know it. Because MyListFragmentView contains fragment in xml definition, so although I called replaced, the method didn't replace actions_list_fragment with new one but put new one after actions_list_fragment. That's why layout_weights made it work - there were two childs in root LinearLayout but I though there is only one.

Related

ViewBinding - How to switch/choose layout dynamically (<include>)?

I was planning on having two layout versions for the profile fragment, one for new user and one for logged in user.
How would I dynamically switch/choose the necessary layout in the Fragment's onCreateView() method?
The most straight-forward idea that comes to mind is to use two <include> layouts and hiding one of them in onCreateView() depending on variables. But I was wondering if there is a smarter approach.
Current layout xml:
The main content is inside the second FrameLayout and I'd like to have two versions to choose from.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".ui.MainActivity">
<ImageView
android:id="#+id/profile_monk_head_imageview"
android:layout_width="match_parent"
android:layout_height="200dp"
android:contentDescription="#string/profile_monk_image_content_desc"
android:src="#drawable/monk_head" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- This is what I want to switch out -->
<FrameLayout ... >
</androidx.core.widget.NestedScrollView>
</FrameLayout>
Use DataBindingUtil version inflate if layoutId is unknown in advance ( a.k.a dynamic binding). Otherwise, use the generated Binding's inflate method to ensure type-safe inflation.
Crosslink reference

Swiping a fragment not full page.

I currently have 1 activity that jas 2 fragments top half and botton half. I want to swipe the bottom fragment only. (java implented)
Before i go learning the wrong method could someone please tell me which method I should use.
Do you sill use pageView and a fragment adapter or something.
Any usefull tutorials that do similar would be good so i can figure it out.
Define fragment and viewpager in the same activity. in the fragment show thetop fragment and in viewpager, write one pager adapter and invoke all the child fragments into that pager. This solves your problem.
Your activity layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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/layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<space
android:id="#+id/layout"
android:layout_width="match_parent"
center_horizontal="true"
center_vertical="true"
android:layout_height="0.5dp">
<fragment
android:id="#+id/layout"
android:layout_width="match_parent"
layout_above="#id/space_layout"
android:layout_height="match_parent"/>
<android.support.v7.widget.viewpager
android:id="#+id/layout"
android:layout_width="match_parent"
layout_below="#id/space_layout"
android:layout_height="match_parent">
Then define PagerAdapter class and show all your child fragments in that.
all the best

getChildFragmentManager > beginTransaction > replace > commit: no result

I have main activity with only ViewPager on it. The first tab page fragment contains:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/llEventsTabPage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/lvEvents"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
I want to show details fragment when user taps item in ListView:
lvEvents.setAdapter(adapter);
lvEvents.setOnItemClickListener(
new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
Fragment eventFragment = new EventFragment();
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.llEventsTabPage, eventFragment);
fragmentTransaction.commit();
}
}
);
Code 'fragmentTransaction.commit();' is called, onCreateView of EventFragment is called, but after 'fragmentTransaction.commit();' nothing happens. No errors, no result. Just list view is still displaying and working.
What am I doing wrong? I've found a few examples, my code looks the same, but not working and I can do nothing with that.
Thank you!
When you do a replace or add, all it's going to do is add the Fragment's View to the container that you specify. The only difference is this:
replace will remove the first existing Fragment inside the container previously that is handled by the FragmentManager specified.
add will simply add the Fragment to the container.
In your case, you have a LinearLayout container which holds a ListView that is of size match_parent. What this means is, when the ChildFragmentManager adds your Fragment to the container, it will add it to a LinearLayout. The fragment is actually below the ListView outside the scope of the View.
Change LinearLayout to FrameLayout and your Fragment will appear over the ListView.
I'm not be sure. but I use two layout structures.
first layout structure
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
in this case, you need two fragment.
one is a EventFragment and other one is a Fragment for ListView.
so you should additionally create fragment for ListView.
second layout structure
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<FrameLayout android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
in this case, you commit R.id.fragment_container instead R.id.llEventsTabPage.
I think it would operate....

Android ListFragment #id attribute

I place two ListFragment in my MainActivity.
This is the ListFragment xml file: fragment1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawSelectorOnTop="false" />
</LinearLayout>
My question is, why must I use android:id="#id/android:list" here? When I use, e.g., #+id/frag_list, the program crashes with Error "inflating class fragment".
ListActivity has a default layout that consists of a single, full-screen list in the center of the screen. However, if you desire, you can customize the screen layout by setting your own view layout with setContentView() in onCreate(). To do this, your own view MUST contain a ListView object with the id "#android:id/list" (or list if it's in code). Its same when your class extends ListFragment.
For more info do check the docs
http://developer.android.com/reference/android/app/ListActivity.html.
You can extend Fragment instead of ListFragment. Have a custom layout with ListView. Then you can provide any id for your listview.

Android: Replacing a fragment in a composite layout

I'm trying to replace a fragment in a composite layout. Here's my root layout XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/buttons"
android:name="com.kippygo.android.touch_talker.ButtonsFragment"
android:layout_width="200dp"
android:layout_height="match_parent"
class="com.kippygo.android.touch_talker.ButtonsFragment" >
<!-- Preview: layout=#layout/buttons_fragment -->
</fragment>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/buffer"
android:name="com.kippygo.android.touch_talker.BufferFragment"
android:layout_width="match_parent"
android:layout_height="80dp" >
<!-- Preview: layout=#layout/buffer_fragment -->
</fragment>
<FrameLayout
android:id="#+id/grid_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground" >
</FrameLayout>
</LinearLayout>
</LinearLayout>
As you can see, I have three areas in my layout, a fixed left column containing a fragment with buttons the rest of the layout is divided vertically with a fragment managing a textView at the top and a grid of data in the lower section.
I want to use a common layout to place various GridView elements in the "grid_frame" as I press buttons in the "buttons" fragment. Here is the "grid_fragment" layout that I want to use for each GridView fragment:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/grid_fragment_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical">
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="80dp"
android:clipToPadding="true"
android:gravity="center"
android:horizontalSpacing="20dp"
android:numColumns="auto_fit"
android:orientation="vertical"
android:stretchMode="columnWidth"
android:verticalSpacing="20dp" >
<!-- Preview: listitem=#android:layout/simple_list_item_2 -->
</GridView>
<TextView
android:id="#+id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="22sp"
android:textStyle="bold"
android:text="#string/no_list_items"/>
</LinearLayout>
This composite layout opens up fine when I start my app. and I set my first fragment in the FrameLayout id "grid_frame" in my initial activity with the following code:
// Execute a transaction to put the categoriesFragment in the grid_view
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.grid_frame, new CategoriesFragment(), "category_fragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
This works perfectly fine and I see my buttons on the left, text input box on top and a grid of nicely filled cells to the right of the buttons.
When I click one of the list items in the GridView presented by the dynamic fragment I want to replace the fragment in the "grid_frame" FrameLayout. I do this with the following code in the onItemClick listener method of the "grid_frame" fragment with the following code:
// Execute a transaction to put the categoriesFragment in the grid_view
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.grid_frame, categoryWordsFragment, "category_words_fragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
Which looks remarkably similar to the code I used in the activity to set the initial fragment which worked fine.
When I do this my entire screen is replaced with the new fragment layout, which is another GridView with different data. My root layout appears to be totally replaced with the layout that was inflated by the new fragment even though I specify the "grid_frame" FrameLayout as the container view id in the replace method call.
I have tried everything I can find to make my layout stay intact and just change the fragment in the FrameLayout container.
What am I doing wrong please?
Problem solved! It was a very stupid mistake. I had converted my Activity classes to Fragment classes and in this one class I had forgotten to remove the call to setContentView in the class onCreate method. So the fragment was setting a new layout each time I created a new instance

Categories

Resources