This is a dumb question and I know the answer is sitting in front of me, I'm just having trouble searching for it in the right way.
I've got a custom view that has been set as the content view and inflated from xml. How can I access the instance to call methods on it from the activity class? I remember seeing something akin to getResourceById() a while back, but now I can't seem to find it and I'm not even sure if that's the best way to do it.
Sorry for the dumb question.
If you have used an inflater, you will be given an instance of a View class. You then use your instance like so
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = li.inflate(R.layout.small_listview_row, null);
TextView tvItemText = (TextView)row.findViewById(R.id.tvItemText);
Related
TL;DR: Is there anything in com.android.layoutlib.bridge.android.BridgeContext that can substitute for Activity#findViewById(...)? I've looked at the source, but I can't find anything.
When running on a real device, an attached view's #getContext() returns the Activity. The view can cast it and call #findViewById(...) to obtain a reference to some other view.
But when running in a WYSIWYG editor, #getContext() returns an instance of a different class. I'm getting com.android.layoutlib.bridge.android.BridgeContext. This class isn't part of the public API, so I'm planning to access it via reflection and degrade gracefully if the implementation changes.
If you're wondering why my view wants a reference to another view... I've created a view that appears to have a hole in it. It works by delegating its drawing to another view. If the view with the hole is placed on top of other views, then it appears to punch a hole through any views beneath it, all the way down to the view it's using for drawing. It works perfectly on a real device, but it would be nice to have it also work in the WYSIWYG editor.
It's bad to assume that View.getContext(), or any other platform method that returns Context, can be cast directly to more concrete classes, like Activity. There exist classes like ContextThemeWrapper which can easily destroy your assumption.
I would recommend restructuring what you are doing so that you have a parent layout that can act as an intermediary for the hole-y View and what's below it.
Or you could have a setter which would provide the View for you.
A last option is to call View.getParent() a bunch of times to get the root View and call findViewById() on that:
ViewParent parent;
while(getParent() != null) {
parent = getParent();
}
View root = (View) parent;
root.findViewById(R.id.my_view);
BTW, BridgeContext is used in the WYSIWYG in place of Activity because it only mocks the Android View/Layout/Rendering system, it doesn't emulate it completely. This can be seen in other ways like how it renders shadows or shape drawable rounded corners.
I awarded the bounty to dandc87 because his answer led me to the solution. However, the code snippet in his answer crashes with a ClassCastException because the root ViewParent is not a View. The mods keep rejecting my edits, so here's the complete and correct solution:
private View findPeerById(int resId) {
View root = this;
while(root.getParent() instanceof View) {
root = (View) root.getParent();
}
return root.findViewById(resId);
}
Solution
Thanks to a clue in codeMagic's answer, the solution to the problem was to set the width and height using the setWidth() and setHeight() methods
Question
I am trying to display a PopupWindow in Android using the following code but it doesn't seem to be working
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
PopupWindow test = new PopupWindow();
test.setContentView(inflater.inflate(R.layout.test, null, false));
test.showAtLocation(findViewById(R.id.main_container), Gravity.CENTER, 0, 0);
}
....
}
Can you tell me where I am going wrong?
EDIT:
What I expect a popup windows to show contain my layout in R.id.test but when i execute the code above, nothing happens. No error or whatsoever
EDIT2:
Added some context to the original code
I decided to use a PopupWindow for what I'm working on now. Mine is in a ListView so it may be a little different but I had to change a couple things to see it. Here are a few things I would suggest to look at because I don't see anything obviously wrong with your code.
Inflate your View first and make sure it doesn't return null
Use a different constructor ( I used new PopupWindow(holder.textNotes, 500, 500, true);
- Replace holder.textNotes with your inflated View and the sizes with something suitable for the screen you are working on.
Note I used this constructor so I could make it focusable for an EditText
3 .I gave my View a background color so I could make sure it was showing
There are several different constructors you can use when creating an instance of PopupWindow which you can find here in the Docs. The one I have used above allows you to set the height and width of the window. This prevents the need for the calls, setHeight() and setWidth() as pointed out by vidhu in the comments.
You should call method update
to display your popup
I'm new to Android and find it brutal (there seems to be an near infinite number of details and dependencies to remember).
Anywho, I got the TextSwitcher1 example app working, which uses ViewSwitcher. I'm assuming ViewSwitcher is the way to go, need to either display a map or a table, user can pick, and switch back and forth.
So I created my MapActivity in another application, seems to work. Next integrate into main app. So, call
View v = findViewById(R.layout.mapview);
and then
mSwitcher.addView(v);
except "v" is null. Why? Do I create the activity? But I don't want to show it yet. Is there such a call as "create activity but hide it until needed"? Or am I barking up the wrong tree?
Thanks for any insight.
The findViewById function returns a View based on an ID resource (R.id.something) for whatever view you have loaded in your activity (using setContentView(R.layout.main)). In your sample code, you're using a layout resource (R.layout.mapview). You should inflate the XML file, which will return a View that you can use to add to the ViewSwitcher.
Example Code:
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.mapview, null);
mSwitcher.addView(v);
However, you should be able to define everything in your XML file and not have to manually add the pages to your ViewSwitcher. Here's some example code on how to do that: http://inphamousdevelopment.wordpress.com/2010/10/11/using-a-viewswitcher-in-your-android-xml-layouts/
In my application I have 2 layouts. One's is root layout that changes dynamically and the second is just a form that opens many times. The form must be child of the root layout but I'm failing to perform so.
I assume that I should simply use:
main.AddView(formLayout)
but I can't figure out how get this formLayout object.
Will thank you for possible answers.
Sounds like you need the LayoutInflater object Android reference.
This allows you to create an object from the xml layout in your project.
With the advice of cjk I wrote piece of code that actually answers my question:
setContentView(R.layout.main);
main = ((ViewGroup)findViewById(android.R.id.content));
LayoutInflater inflater = this.getLayoutInflater();
ViewGroup form= (ViewGroup) inflater.inflate(R.layout.formLayout, null);
main.addView(form);
Thank you all
Not sure if I understand the question properly, but something like that might work:
View myView;
myView = (View) this.findViewById(R.id.formLayout);
main.addView(myView);
By get I figure you mean you want to retrieve a field in the new opened layout, you can do it by making it a new Intent and using startActivityForResult instead of startActivity.
I am trying to register a context menu in a skeleton app's OnCreate():
/** Called with the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate our UI from its XML layout description.
setContentView(R.layout.skeleton_activity);
View v = findViewById(R.layout.skeleton_activity);
registerForContextMenu(v);
// Find the text editor view inside the layout, because we
// want to do various programmatic things with it.
mEditor = (EditText) findViewById(R.id.editor);
// Hook up button presses to the appropriate event handler.
((Button) findViewById(R.id.back)).setOnClickListener(mBackListener);
((Button) findViewById(R.id.clear)).setOnClickListener(mClearListener);
mEditor.setText(getText(R.string.main_label));
}
The debugger tells me that findViewById(R.layout.skeleton_activity) returns null.
#CommonsWare solution to a similar post is to Wait until onFinishInflate(). However, in the sample project he provides, it doesn't seem that he waits until onFinishInflate.
My questions:
Can registerForContextMenu() wait
until onFinishInflate()?
If so, how do I do so?
This line is not correct its asking for id and you are providing layout
View v = findViewById(R.layout.skeleton_activity);
Instead if you want to have object of your root layout element then provide it some id and then try something like this
View v = findViewById(R.id.root_element);
I think you should use
View v = findViewById(R.id.skeleton_activity);
instead.
For the 2nd question, sorry, I 've no idea. Hope to see someone else's answer.
You shouldn't need to wait for the content to inflate in an Activity.
One problem is that findViewById takes an ID (R.id....) when you provide it with a layout (R.layout...). Can you try the following instead, to reference the Activity's root view?
setContentView(R.layout.skeleton_activity);
View content = findViewById(android.R.id.content);
registerForContextMenu(content);
i think the code you have shown is very confusing. Here is a good article http://blog.sptechnolab.com/2011/02/10/android/android-contextmenu-submenu/. In my case it works, i hope you can solve your problem.