what happens when a view id is used for setContentView() - android

The Android developer guide seems to suggest that Activity.setContentView() can only be called with a layout ID (R.layout.*). However, I can see view IDs (R.id.*) being used to call the method. For example, in org/xbmc/android/widget/slidingtabs/SlidingTabActivity.java of XBMC, I can see the following code:
private void ensureTabHost() {
if (mTabHost == null) {
this.setContentView(R.id.slidingtabhost);
}
}
So, what does it mean to call setContentView() with a view ID? Thanks!
Additional question based on comment - is "setContentView(viewId);" equivalent to "View v = findViewById(viewId); setContentView(v);"?

Not
that Activity.setContentView() can only be called with a layout ID (R.layout.)
Just any view id can be called by the setContentView().
And layout is also a view!

I think the document should say:Set the activity content from a view(not only a layout) resource. The resource will be inflated, adding all top-level views to the activity. Actually ,it works like this: If you make a setConentView(R.layout.my_layout); then android os will do the following works:
LayoutInflater inflater= (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.my_layout, null);
setConentView(layout);
if you make a setContentView(R.id.myview);it is also the same way to inflate.
LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View myview = inflater.inflate(R.id.myview, null);
setConentView(myview); `
So I say they are the same.

Related

inflate view returns the old inflated result

I try to inflate a layout multiple times to be inserted inside another layout. Here is the code:
View oldView = null;
for (ProfileServiceCategory.ProfileService service : profileServiceCategory.getServices()) {
View view = LayoutInflater.from(context)
.inflate(R.layout.profile_service_list_item, viewHolder.rootView);
if(oldView == view) {
Log.d("test", "Error");
}
oldView = view;
TextView serviceName = (TextView) view.findViewById(R.id.profile_services_name);
serviceName.setText(service.getServiceValue());
}
The problem that I'm facing is the view variable that is being returned by inflate method is always the first inflated view. To be clear I added a Log.d , if everything worked as expected it should have been never called but it does hit.
I checked the view hierarchy and I can conform that new views in fact has been added to rootView but the reference that I get is for older view.
One of my colleague suggested a workaround by adding the view manually to container. Here is the edited code:
LayoutInflater layoutInflater= LayoutInflater.from(context);
for (ProfileServiceCategory.ProfileService service : profileServiceCategory.getServices()) {
View view = layoutInflater.inflate(R.layout.profile_service_list_item, null);
TextView serviceName = (TextView) view.findViewById(R.id.profile_services_name);
serviceName.setText(service.getServiceValue());
viewHolder.rootView.addView(view);
}
When null is getting passed to inflate method as second argument a new view gets returned each time. The view can be inserted inside the container by addView method.
This is obviously a bug in android SDK.
LayoutInflater.from(context).inflate(R.layout.profile_service_list_item,
viewHolder.rootView);
is always returning the same inflater service. so i think you have to take copy of layoutInflater using cloneInContext
View view = LayoutInflater.from(this)
.cloneInContext(R.layout.layout_fullscreen_image, viewHolder.rootView);

Why dynamically create framelayout?

I am trying to understand how the Tinder like/dislike card system works by looking through this example on GitHub: https://github.com/kikoso/Swipeable-Cards/blob/master/AndTinder/src/main/java/com/andtinder/view/CardStackAdapter.java. I understand the importance of BaseAdapters and populating the view/card with the necessary info. This part of the code that is confusing the hell out of me is this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
FrameLayout wrapper = (FrameLayout) convertView;
FrameLayout innerWrapper;
View cardView;
View convertedCardView;
if (wrapper == null) {
wrapper = new FrameLayout(mContext);
wrapper.setBackgroundResource(R.drawable.card_bg);
if (shouldFillCardBackground()) {
innerWrapper = new FrameLayout(mContext);
innerWrapper.setBackgroundColor(mContext.getResources().getColor(R.color.card_bg));
wrapper.addView(innerWrapper);
} else {
innerWrapper = wrapper;
}
cardView = getCardView(position, getCardModel(position), null, parent);
innerWrapper.addView(cardView);
} else {
if (shouldFillCardBackground()) {
innerWrapper = (FrameLayout) wrapper.getChildAt(0);
} else {
innerWrapper = wrapper;
}
cardView = innerWrapper.getChildAt(0);
convertedCardView = getCardView(position, getCardModel(position), cardView, parent);
if (convertedCardView != cardView) {
wrapper.removeView(cardView);
wrapper.addView(convertedCardView);
}
}
return wrapper;
}
Why are FrameLayouts being created dynamically? It seems like multiple FrameLayouts are being made with wrapper and inner wrapper? What does wrapper even mean? Why are classes like shouldFillCardBackground() used but not even defined anywhere in the repository?
First of all, it is important to notice that the CardStackAdapter you link to is abstract, so it will never be instantiated directly. Rather, the class SimpleCardStackAdapter will be used for instance.
That said, lets get the purpose of the method clear; The getView() method's purpose is to create and populate a view for the given position.
Creating layouts can be done either by inflating them from xml, or otherwise, by creating them in code. The latter is happening here. The main reason that they create the layout dynamically, is to keep things dynamic. The exact views in the layout depend on some configurations which are checked at runtime (in the method shouldFillCardBackground()). Note that this could also be achieved by creating the layout in xml, then inflate it, and dynamically hide/show (or remove/add) views and layouts. The auther of the code simply chose to do it in code.
A wrapper is an object (in this case a layout) which does not much more that holding other objects (other layouts). In the context of layouts, they are usually used to add some kind of background or padding. That is also what is happening here.
shouldFillCardBackground() is a method, not a class, and it is definitely defined: in line 71.
It is important to realize that it seems that the main puropose of this code is to be an example, a demo. It is possible it is not fully functional and that not everything is implemented the best way (for instance, shouldFillCardBackground() returns true by default).

LayoutInflater for using xml and View class

after I asked if I should use XML or a View class for my project you told me, that I should do everything possible in XML and use a class for the rest. You told me, that animating Sprites isn't possible with XML so I wanted to make a View Class. I got the tip to google "LayoutInflater" for this and I did.
There aren't many Informations about inflaters so I visited android's developers database and tried to find out how this works.
As far as I know now, you have to put something into the onCreate method of your main game activity (the setContentView has to be the mainXML).
So now I created a LinearLayout in my mainXML and called it "container" and made this being a ViewGroup called "parent".
Now I have created a global variable "private View view" and wrote this line:
view = LayoutInflater.from(getBaseContext()).inflate(new ViewClass(this),
null);
Thw Problem now is that u can't inflate a class like this and I think I'm doing this whole inflating thing wrong.
Do you have any tips and tricks for me for making it work to have a LinearLayout in my mainXML and being able to make the content from my View Class appear in it?
EDIT:
Got it to work without errors, but nothing happens if I start my game now.
Here is the code pls answer if u have any solutions:
super.onCreate(savedInstanceState);
// inflate mainXML->
View mainView = getLayoutInflater().inflate(R.layout.activity_game, null);
// find container->
LinearLayout container = (LinearLayout) mainView.findViewById(R.id.container);
// initialize your custom view->
view = new GameLayout(this);
// add your custom view to container->
container.addView(view);
setContentView(R.layout.activity_game);
And my GameLayout:
public GameLayout(Context context)
{
super(context);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color.BLACK);
}
There are two ways of going about this. I'll show you one of them. Do the following in your onCreate(Bundle) before calling setContentView(...):
// inflate mainXML
View mainView = getLayoutInflater().inflate(R.layout.mainXML, null);
// find container
LinearLayout container = (LinearLayout) mainView.findViewById(R.id.container);
// initialize your custom view
view = new ViewClass(this);
// add your custom view to container
container.addView(view);
Finally:
setContentView(mainView);
Alternatively, you can place your custom view inside mainXML:
<your.package.name.ViewClass
android:id="#+id/myCustomView"
android:layout_width="match_parent"
android:layout_height="match_parent"
.... />

Android: findviewbyid: finding view by id when view is not on the same layout invoked by setContentView

I have an activity MyActivity that extends from MapActivity. In the .xml file containing the layout I can only include the MapView
<com.google.android.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/trail_map_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="key"
/>
However I do need to find another view that is located in another .xml file.
Unfortunately, findViewById returns null.
How can I get the view I am looking for?
Thanks a lot!
Thanks for commenting, I understand what you mean but I didn't want to check old values. I just wanted to get a pointer to that view.
Looking at someone else's code I have just found a workaround, you can access the root of a layout using LayoutInflater.
The code is the following, where this is an Activity:
final LayoutInflater factory = getLayoutInflater();
final View textEntryView = factory.inflate(R.layout.landmark_new_dialog, null);
landmarkEditNameView = (EditText) textEntryView.findViewById(R.id.landmark_name_dialog_edit);
You need to get the inflater for this context, access the root view through the inflate method and finally call findViewById on the root view of the layout.
Hope this is useful for someone! Bye
I have changed in my activity but effected.
Here is my code:
View layout = getLayoutInflater().inflate(R.layout.list_group,null);
try {
LinearLayout linearLayout = (LinearLayout) layout.findViewById(R.id.ldrawernav);
linearLayout.setBackgroundColor(Color.parseColor("#ffffff"));
}
catch (Exception e) {
}
}
try:
Activity parentActivity = this.getParent();
if (parentActivity != null)
{
View landmarkEditNameView = (EditText) parentActivity.findViewById(R.id. landmark_name_dialog_edit);
}
Another way to do this is:
// inflate the layout
View myLayout = LayoutInflater.from(this).inflate(R.layout.MY_LAYOUT,null);
// load the text view
TextView myView = (TextView) myLayout.findViewById(R.id.MY_VIEW);
It's impossible. You can only find and access views that are currently running. If you want to check the value of ex. TextView used in previus activity you must save the value is SharedPreferences, database, file or pass by Intent.
I used
View.inflate(getContext(), R.layout.whatever, null)
The using of View.inflate prevents the warning of using null at getLayoutInflater().inflate().
In main Activity just create Static Variable Like below.
//Create Static variable
public static View mainView;
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.activity_home, null);
mainView = view;
//Now just need to Call MainActivity.mainView to Access your home view or Something else.

How to inflate one view with a layout

I have a layout defined in XML. It contains also:
<RelativeLayout
android:id="#+id/item"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
I would like to inflate this RelativeView with other XML layout file. I may use different layouts depending on a situation. How should I do it? I was trying different variations of
RelativeLayout item = (RelativeLayout) findViewById(R.id.item);
item.inflate(...)
But none of them worked fine.
I'm not sure I have followed your question- are you trying to attach a child view to the RelativeLayout? If so you want to do something along the lines of:
RelativeLayout item = (RelativeLayout)findViewById(R.id.item);
View child = getLayoutInflater().inflate(R.layout.child, null);
item.addView(child);
You inflate an XML resource. See the LayoutInflater doc .
If your layout is in a mylayout.xml, you would do something like:
View view;
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.mylayout, null);
RelativeLayout item = (RelativeLayout) view.findViewById(R.id.item);
Though late answer,
but would like to add that one way to get this
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.mylayout, item );
where item is the parent layout where you want to add a child layout.
It's helpful to add to this, even though it's an old post, that if the child view that is being inflated from xml is to be added to a viewgroup layout, you need to call inflate with a clue of what type of viewgroup it is going to be added to. Like:
View child = getLayoutInflater().inflate(R.layout.child, item, false);
The inflate method is quite overloaded and describes this part of the usage in the docs. I had a problem where a single view inflated from xml wasn't aligning in the parent properly until I made this type of change.
Even simpler way is to use
View child = View.inflate(context, R.layout.child, null)
item.addChild(child) //attach to your item
Try this code :
If you just want to inflate your layout :
View view = LayoutInflater.from(context).inflate(R.layout.your_xml_layout,null); // Code for inflating xml layout
RelativeLayout item = view.findViewById(R.id.item);
If you want to inflate your layout in container(parent layout) :
LinearLayout parent = findViewById(R.id.container); //parent layout.
View view = LayoutInflater.from(context).inflate(R.layout.your_xml_layout,parent,false);
RelativeLayout item = view.findViewById(R.id.item); //initialize layout & By this you can also perform any event.
parent.addView(view); //adding your inflated layout in parent layout.
layout inflation
View view = null;
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.mylayout, null);
main.addView(view);
If you're not in an activity you can use the static from() method from the LayoutInflater class to get a LayoutInflater, or request the service from the context method getSystemService() too :
LayoutInflater i;
Context x; //Assuming here that x is a valid context, not null
i = (LayoutInflater) x.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//OR
i = LayoutInflater.from(x);
(I know it's almost 4 years ago but still worth mentioning)
AttachToRoot Set to True
Just think we specified a button in an XML layout file with its layout width and layout height set to match_parent.
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/custom_button">
</Button>
On This Buttons Click Event We Can Set Following Code to Inflate Layout on This Activity.
LayoutInflater inflater = LayoutInflater.from(getContext());
inflater.inflate(R.layout.yourlayoutname, this);
Hope this solution works for you.!
If you want to add a single view multiple time then you have to use
layoutInflaterForButton = getActivity().getLayoutInflater();
for (int noOfButton = 0; noOfButton < 5; noOfButton++) {
FrameLayout btnView = (FrameLayout) layoutInflaterForButton.inflate(R.layout.poll_button, null);
btnContainer.addView(btnView);
}
If you do like
layoutInflaterForButton = getActivity().getLayoutInflater();
FrameLayout btnView = (FrameLayout) layoutInflaterForButton.inflate(R.layout.poll_button, null);
and
for (int noOfButton = 0; noOfButton < 5; noOfButton++) {
btnContainer.addView(btnView);
}
then it will throw exception of all ready added view.
If you are you trying to attach a child view to the RelativeLayout? you can do by following
RelativeLayout item = (RelativeLayout)findViewById(R.id.item);
View child = getLayoutInflater().inflate(R.layout.child, item, true);
I had the hardest time with this error, because of my unique circumstances, but finally found a solution.
My situation: I am using a separate view (XML) which holds a WebView, then opens in an AlertDialog when I click a button in my main activity view. But somehow or another the WebView belonged to the main activity view (probably because I pull the resource from here), so right before I assigned it to my AlertDialog (as a view), I had to get the parent of my WebView, put it into a ViewGroup, then remove all the views on that ViewGroup. This worked, and my error went away.
// set up Alert Dialog box
AlertDialog.Builder alert = new AlertDialog.Builder(this);
// inflate other xml where WebView is
LayoutInflater layoutInflater = (LayoutInflater)this.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
View v = layoutInflater.inflate(R.layout.your_webview_layout, null);
final WebView webView = (WebView) v.findViewById(R.id.your_webview_id);
// more code...
.... later on after I loaded my WebView ....
// first, remove the parent of WebView from it's old parent so can be assigned a new one.
ViewGroup vg = (ViewGroup) webView.getParent();
vg.removeAllViews();
// put WebView in Dialog box
alert.setView(webView);
alert.show();
With Kotlin, you can use:
val content = LayoutInflater.from(context).inflate(R.layout.[custom_layout_name], null)
[your_main_layout].apply {
//..
addView(content)
}
When add a layout to an Activity in Kotlin, see these steps:
Add just in Activity - One layout as a parent
Xml file of new
Layout Give the value of R.
val parent: LinearLayout =findViewById(R.id.stars)
val view =
LayoutInflater.from(applicationContext).inflate(R.layout.another, parent,false)
Where parent is not necessary, can be null But warning message will be appear
view.findViewById<ImageView>(R.id.ivTimer).setImageResource(R.drawable.t2)
Any view must be set value in this way, finally add
parent.apply { addView(view)}
I had used below snippet of code for this and it worked for me.
LinearLayout linearLayout = (LinearLayout)findViewById(R.id.item);
View child = getLayoutInflater().inflate(R.layout.child, null);
linearLayout.addView(child);

Categories

Resources