I am using the scrolling activity generated by Android Studio. So something like this:
It uses an #include tag in the XML to load the content of the activity.
I need to change the content inside this NestedScrollView to something else. So I have been using this:
LayoutInflater inflater =
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
progressContent = inflater.inflate(R.layout.content_progress, null);
scrollView.removeView(normalContent);
scrollView.addView(progressContent);
And it works, but it doesn't use the ConstraintLayout of the progressContent correctly, it ignored all the bias values and only keeps hard set margins and paddings.
In this question, people suggested to use ´setContentView` but since I only have to change the inner content, not the whole layout, it's not the right solution:
How to set layout dynamically in android
In this one it was suggested to use ViewStubs instead of #include:
How can I programmatically include layout in Android?
But this only resulted in a completely broken CollapsingToolbarLayout and the layout parameters of the second view got discarded regardless.
What is the correct way of doing this?
Related
inflater.inflate(R.layout.fragmenta , container , false);
We use this line of code for inflating. Despite read documentary , i didn't understand what is the second and third parameters function is ? What is the root in this situation and what happen if i change third to true ?
In your layout XML file some of the attributes relate to the parent container. Anything that starts with layout_*. The container, or parent in some cases, is needed to resolve those values. You can see this with things like layout_margin. If you don't give the inflater a parent you won't have any margins. But if you wrap your layout in another container like a frame layout it works. That's because it's able to resolve layout_margin using the frame layout. I'm not completely sure about the attach to parent boolean. I always get Exceptions when I set it to true.
Layout Inflater
The video should give you a good explanation of what is done and why it is done.
I have a requirement where there are 2 programatically generated screens and 2 xml layouts. Now i need to on the fly combine, these layouts multiple times.
For ex, i have screen 1 - programatically created, screen 2 - programatically created, screen 3- from a xml layout, screen 4 - from a xml layout
My final layout design should be a single screen with screen1, screen2, screen 3, screen 4, screen 2... with all screens sharing equal screen space based on the number of screen i input. Please let me know the approach. Some screens are having relative layout and some linear ones. So it should combine these.
You'll need to invoke addView() on the primary layout. Once the primary layout is built (which holds all the other layouts), the addView() method will add new views to the existing primary layout.
To add the new layout, you'll need to inflate it first.
LinearLayout primaryLayout;
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
LinearLayout newLayout = (LinearLayout)layoutInflater.inflate(R.layout.your_new_layout, null, false);
primaryLayout.addView(newLayout);
AddView also provides an index option to place the new layout at a specific point in the primary layout.
Try starting with a blank, XML layout (say called primary_layout):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/primaryLayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</RelativeLayout>
Then, as your activity starts, set that first, then inflate and add as desired:
setContentView(R.layout.primary_layout);
LinearLayout primaryLayout = (LinearLayout) findViewById(R.id.primaryLayout);
Then you can add your new views to that one. As for adding multiple times, I believe that it's done by reference, so it only sees a single view. Try building the view in a method, and just returning the view. Such as:
private View buildNewView(){
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
LinearLayout newView = (LinearLayout)layoutInflater.inflate( R.layout.my_new_view null, false );
return newView ;
}
And call it via primaryLayout.addView(buildNewView();.
You could look into Fragments. They seem to do exactly what you need. Here are the links to the Training and API Guides on them.In your xml file, you can specify 4 child layouts inside a LinearLayout parent, each with an attribute android:layout_weight="1", so each child layout would only take up the same amount of space. If in portrait orientation, it is suggested to set android:layout_width="match_parent and android:layout_height="0dp" Now, you can label the id's of each child layout as id1, id2, id3, etc, but you can also label the two layouts you will create as something likeandroid:id="#+id/fragment_container_first and android:id="#+id/fragment_container_second.In the Java code, you would set the contentView as the id of the xml file (setContentView(R.layout.myXMLLayout);), create two instances of a Fragment by following the Training guide link I provided above, and add those views to the containers you setup earlier inside your xml files by using something like getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container_first, firstFragment).commit(); and getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container_second, secondFragment).commit();(If you are using the support library, which is what the training guides use).I really hope this helps you out. You can build a really flexible UI with Fragments. For instance, later on, you can replace the first two fragments with other fragments at runtime, increasing flexibility. You can even setup different UIs for different screen sizes, with a more compact view on a phone, but with much more to offer on a larger screen like a tablet.I'd love to hear back if this helped you out!
Short Story:
I have a layout "layout.xml", which gets replaced by another layout "success.xml" after a successful web request. Both layouts have an ImageView that provides the backgrounds to the layouts. These 2 backgrounds both need to be the same, and both are dependent on a user preference.
Longer Story: This all happens in a Fragmnet with an AsyncTask replacing the contentView with "success.xml" in onPostExecute after the web request. This happens as follows:
View view = getView();
view = null;
view = View.inflate(context, R.layout.success, null);
What I tried to do is give both ImageViews the following android:id="#+id/background_image" and then call
ImageView background = (ImageView)view.findViewById(R.id.background_image);
background.setImageResource(R.drawable.bg1);
This background-setting works for the initial view (layout.xml), but on trying to change to "success.xml", I get a NullPointException because background is null.
I've checked and the View's id is set to -1 while the original view's background_image id is set to something sensible and valid.
I've also tried setting the second view's background id like this: android:id="#id/background_image", i.e. without the '+', but still no luck.
The added complication is that it's not just 2 layouts, but about 5 that I need to do this for, so it would be really handy to recycle view id's.
Any help would be greatly appreciated.
Your code for replacing the fragment's view will not do what you want, the original view will remain the same as you change only a reference to that view and not the actual object.
To replace the view of the fragment with the new layout you could have another ViewGroup(for example a FrameLayout) in the basic layout (layout.xml) wrapping your current content(don't forget to give it an id) of layouts.xml(as I understand this is the basic layout). Then, when it's time to replace the layout you could simply do:
// remove the current content
((ViewGroup) getView().findViewById(R.id.yourWrapperLayout)).removeAllViews();
// add the new content
View.inflate(context, R.layout.success, ((ViewGroup) getView().findViewById(R.id.yourWrapperLayout)));
You could avoid adding an extra layout if, by any chance, all your five layouts have the same type for the root view(like a LinearLayout etc). In this case you would use the same code as above but you'll modify the other layouts file to use a merge tag. Also, you'll be looking for the id of the root in the layout.xml layout into which you'll add the content of the other files.
Then you could have the same ids, but you'll have to reinitialize any reference to the views(meaning that you'll have to search for the view again if you store a reference to the view(like a Button field in the fragment class)).
I have a complex empty view in a layout, with an icon, text, button, etc.
It is easy to select a view within my layout.xml to use when the listview is empty, similar to
getListView().setEmptyView(findViewById(R.id.empty));
This code sets the empty view works just fine when it resides in the layout.xml file.
Now I want to refactor this view into its own empty.xml layout file, and have coded it similar to the following:
// Setup the empty layout.xml
LayoutInflater vi = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View vlEmpty = vi.inflate(R.layout.empty, null);
// Find the empty layout view
vEmpty = vlEmpty.findViewById(R.id.llEmpty);
vEmpty.setOnClickListener(ocl);
// Find the ListView
vListView = (ListView) findViewById(R.id.lvWords);
vListView.setEmptyView(vEmpty);
The problem is that the details within llEmpty never show up; The exact same layout and view works withing the main layout, just not refactored into its own xml file.
Has anyone got something like this to work?
You might need to pass the proper context to the inflater:
vListView = (ListView) findViewById(R.id.lvWords);
View vlEmpty = vi.inflate(R.layout.empty, (ViewGroup)vListView.getParent());
which (should) make them both live in the same root view. It may be sufficient to just pass the root view of the parent activity.
Let me know if that works.
I doubt that setEmptyView() automatically makes the supplied View a child of any container in your activity.
Personally, I'd just use the <include> element rather than inflating it separately. But, if you really want to inflate it separately, the answer that Femi posted while I was writing this may work, depending on what the ListView's parent is.
I want to bind data from an xml file? how can I do that where i'm using a layout xml file to define a scrollview ??
If i've understood your question right, you want to read a layout file and insert it into a ScrollView.
You would want to take a look LayoutInflater for this task.
Example for doing this from an activity.
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ScrollView sv = findViewById(R.id.id_of_scrollview);
inflater.inflate(R.layout.id_of_layoutfile_to_include, sv);
EDIT:
After having read your comment i realise that i misunderstood your question.
ScrollView is not the view you want for binding your data, scrollView is a specialized frameLayout, and therefore only allows one child.
Your most likely looking for a view like ListView (Which adds scrolling automatically)
Another solution is to use a Layout in a scrollview and dynamically (From code) add the views.
LinearLayout ll = findViewById(R.id.id_of_linearlayout);
//Loop data and build a view for each data entry and add it with
ll.addView(yourView);