I want to achieve this :
Create a ViewDataBinding by inflating a layout.
Set a tag to its root view.
Insert its root view into my layout.
Later on, call findViewWithTag() to retrieve its root view.
Getting the ViewDataBinding linked to its view.
But I can't figure out how to achieve the latest step.
This is how my code looks like :
MyViewDataBinding binding = DataBindingUtils.inflate(inflater, R.layout.my_layout, myContainer, false);
View bindingRootView = binding.getRoot();
bindingRootView.setTag("aTag");
myContainer.addView(bindingRootView);
//In another part of the code ...
MyViewDataBinding binding = myContainer.findViewByTag("aTag").getViewDataBinding();
But is their something like "getViewDataBinding"?
Thank's for help.
You can find appropriate method in DataBindingUtil class. It is called findBinding(View view). It may be needed to cast returned value to your wanted class type.
I'm not sure though whether it's the best architecture. I would be interested if you would give us more context.
Related
While trying to convert an application from the defunct Kotlin synthetics to the newer/supported view binding method, I ran into this issue where layouts are being inflated in a loop and attached to the target parent view:
for (item in itemList) {
val view = LayoutInflater.from(this).inflate(R.layout.imageitem_row, binding.linear, false)
view.text1.text = item.title
view.text2.text = item.pubdate
binding.linear.addView(view)
}
Since Kotlin synthetics are being removed from the code, text1 and text2 are not valid properties of view. So how do I apply view binding to this inflated layout? Or does that not work here and I should be using findViewById() instead for text1 and text2?
Just to explain what's going on - with the synthetics library, it was basically doing view binding in the activity itself (or whatever). For each view with an id in your layout, it was adding a property you could access directly. So you could just call text1.text in the current scope, and that would have been automatically bound to a view in the hierarchy.
With view binding, there's no magic and no throwing properties into that top-level scope. Instead, each layout has an automatically generated class with Binding added to the end of the name, like ImageItemRowBinding. This class has a property for each view with an id, so it's all encapsulated in one place.
You either call bind(view) on it to get an instance with all the properties assigned (by finding them in the view hierarchy you pass in), or you can call inflate if you don't have the view yet, and you want it to inflate that while it's binding. You end up getting back an instance of the binding class with all the view properties assigned (and you can access the top of the view hierarchy through the root property).
Aside from that, it's basically the same! You just have to manually create your binding instances, and access your views through that. Don't forget you can use Kotlin functions like with(binding) or binding.run { } to work with its properties without needing the binding prefix every time, so you can pretty much just wrap your original synthetics-based code if it's convenient
Here is the tutorial
https://www.youtube.com/watch?time_continue=289&v=OGfZpfn-dGI
In my android studio it doesn't recognize the button iv'e name them
android:id="#+id/top_button"
android:text="top button"
android:text="button 2"
android: android:id="#+id/button_2"
top_button.setOnClicklistner {
println(top button was clicked)
Button_2.setOnClicklistner {
println(Button)
We're missing a lot of context here that would probably help us help you.
A few things first though:
- The android:id property in your XML layout is how you name the View in question. This is most often how you will reference the View in code.
- The android:text property is the user visible text on views like TextView.
- In order for top_button to refer to your desired View in your XML layout file, it needs to be bound in code. There's a couple of normal ways of doing it findViewById() and data-binding.
I'm going to assume, for now, that the last step is what you are missing (it seems the most likely culprit at this point)... Here's a few ways to bind it:
Method 1: when using an Activity class
If you're binding top_button to your View from an Activity class, this should work:
private lateinit var top_button // replace View here with your widget's type
fun onCreate(...) {
super.onCreate(...)
setContentView(R.layout.<i>your_layout_file_name_here</i>)
top_button = findViewById(R.id.top_button)
...
}
Method 2: when using a Fragment class
If you're binding top_button to your View from a Fragment class, it's more like this:
private lateinit var top_button: View // replace View here with your widget's type
fun onCreateView(...): View {
val rootView = layoutInflater.inflate(R.layout.<i>your_layout_file_name_here</i>)
top_button = rootView.findViewById(R.id.top_button)
...
return rootView
}
Method 3: when using data-binding
I prefer this method myself, but you should Google how to setup data-binding in Android as you'll need changes in your build.gradle and all.
First, change your XML layout to be:
<layout>
<!-- your existing layout XML here -->
</layout>
Then in your Activity/Fragment, let's say your XML layout file is named activity_my_cool_screen.xml, you can do:
val binding = ActivityMyCoolScreenBinding.inflate(getLayoutInflater())
binding.topButton.setOnClickListener(...)
Notice here that the ActivityMyCoolScreenBinding class is auto-generated for you. If it turns red at first, then first verify you've accurately setup data-binding in your project, then if that's good to go, make sure to import the ActivityMyCoolScreenBinding class. If you change your XML layout's filename, then the ActivityMyCoolScreenBinding class name will change to match automatically. But, I'd recommend if you do change the name, that you use Android Studio's refactoring/renaming tools as it'll search your codebase and update it everywhere. Otherwise, you have to do it by hand (doable, but potentially tedious and error prone).
Good luck!
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);
}
I am new in android.I have a simple doubt,Is there any way to get id of a widget from some layout without set it as content view ?? I am looking to invisible a view from a class .I used the code
View b = findViewById(R.id.id2);
b.setVisibility(View.GONE);
But error in "id",is it possible to get ids if widget from a java class without set as contentview ?? please help me. Thanks in advance :)
You can inflate the views separately and then use findViewById on the root of the inflated layout.
// inside of Activity, you can use 'this' for the context
LayoutInflater inflater = LayoutInflater.from(context);
View root = inflater.inflate(R.layout.some_layout);
// from your example
View b = root.findViewById(R.id.id2);
b.setVisibility(View.GONE);
At this point however these views are not part of your Activity's view hierarchy and will not be seen by the user. You will have to add them either by using setContentView(root) or by finding a ViewGroup in the current view hierarchy and calling viewGroup.addView(root).
You can do it this way
Button filterButton = new Button(YourActivity.this);
filterButton.setVisibility(filterButton.GONE);
onCreate(Bundle) is where you initialize your activity. Most importantly, here you will usually call setContentView(view) with a layout resource defining your UI, and using findViewById(int) to retrieve the widgets in that UI that you need to interact with programmatically.
See below link :-
Why findViewById() is returning null if setcontentview() is not called?
'But error in "id",is it possible to get ids if widget from a java class without set as contentview ?? '
You have to create dynamic view then you do not have need to call setcontentview.
how to set setContentView?
Is there a way to set setContentView(int id) dynamically?
I have a big problem. In systemUI/PhoneStatusBar class, I want to add a childView to parrent of current View of running Activity. How to done it in PhoneStatusBar.java in systemUI.
I tried to using some method, example
View.getRootView()
or so on, but cannot get expected result.
Hope to get success from everyone. Thanks very much
Thanks for help from you. But i would like to emphasized that "I want to get current view of running activity". I it must be done in android/frameworks/base/packages//Systemui/statusbar/phone/PhoneStatusBar.java.
I very very hope to continue receiving helps from everyone
Try
View.getContext();
It should work.
To add a view, you need to cast it as a ViewGroup:
ViewGroup addViewHere = (ViewGroup)myView;
Or you may need to get the parent if the problem is that you cannot add the view to the correct place in the view hierarchy:
ViewGroup addViewHere = (ViewGroup)myView.getParent();
Then assuming all layout params are correct, add it:
addViewHere.addView(newView);
You can try this:
findViewById(android.R.id.content).getRootView()
It should give you the root view of the activity including status bar on top