I know that I can set the content of the view in an Android app by saying setContentView(int). Is there a function I can use to know what the current content view is? I don't know if that makes any sense, but what I'm looking for is a function called, say, getContentView that returns an int.
Ideally, it would look like this:
setContentView(R.layout.main); // sets the content view to main.xml
int contentView = getContentView(); // does this function exist?
How would I do that?
Citing Any easy, generic way in Android to get the root View of a layout?
This answer and comments give one method: [Get root view from current activity
findViewById(android.R.id.content)
Given any view in your hierarchy you can also call:
view.getRootView()
to obtain the root view of that hierarchy.
The "decor view" can also be obtained via getWindow().getDecorView(). This is the root of the view hierarchy and the point where it attaches to the window, but I'm not sure you want to be messing with it directly.
You can do making a setter and getter of current view by id only
private int currentViewId = -1;
public void setCurrentViewById(int id)
{
setContentView(id);
currentViewId = id;
}
public int getCurrentViewById()
{
return currentViewId;
}
And then in
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setCurrentViewById(R.layout.main_layout);
}
Hope this helps.
In an Activity, you can do
View rootView = null;
View currentFocus = getWindow().getCurrentFocus();
if (currentFocus != null)
rootView = currentFocus.getRootView();
As described above, there is also
View decorView = getWindow().getDecorView();
as well as
View decorView = getWindow().peekDecorView();
The difference between the latter two is that peekDecorView() may return null if the decor view has not been created yet, whereas getDecorView() will create a new decor view if none exists (yet). The first example may also return null if no view currently has focus.
I haven't tried out whether the root view and the decor view are the same instance. Based on the documentation, though, I would assume they are, and it could be easily verified with a few lines of code.
if you have two content views then you can put a tag inside the relative layout of each one. and then get the view by tag name. if tag name is the one desire then blablabla. Hope this help for whoever is searching for a solution.
Related
I am trying to optimize old code. And I am trying to replace findviewbyid with viewbinding.
But how do I return viewbinding id instead of findviewbyid?
private TextView getTextView(int id){
return (TextView) findViewById(id);
}
This is the old code. But I want to apply viewbinding. I want it to work something like this. As I have no idea how to do it.
private TextView getTextView(int id){
return sampleViewBinding(id);
}
How can I achieve this?
The whole point of View Binding is to avoid findViewById() calls. It does it for you automatically. What you are trying to do is treating View Binding like findViewById(). Whenever you need to access any view, all you have to do it call the generated binding class with your id in the camel-case. for e.g main_layout.xml is gonna have a class generated by the name MainLayoutBinding so you are going to access all the view inside your layout by calling the MainLayoutBinding's instance and the id you want to access.
If your layout file name is fragment_dashboard.xml and has within a textview with an Id userNameTvId, then you normally do this without using data binding:
val view = inflater.inflate(R.layout.fragment_dashboard, container, false)
val textview = view.findViewById(R.id.userNameTvId)
but with viewBinding it is done by chaining. this textview is acceptable through the binding object. The above will be rewritten like this using viewBinding:
val binding = FragmentDashboardBinding.inflate(inflater)
binding.userNameTvId
// to pass a value you can just do
binding.userNameTvId = "SomeOne"
val view = binding.root
I know it's not the best practice, but I have a few layouts (only one is visible at a time)
with the same view_id in all of them.
Is there any way method to get all views with this id?
I can iterate all layouts and layout.findViewById() but wanted to ask if there is something similar to a CSS findViewsById() views instead of view
Activity::findViewById() returns just the first one.
No, there is no method like that. If some "dirty hack" exists it will be unstable.
"Best practice" here will be iterate layouts and store references on these views in array.
You can make your own. In that case you have to use setContentView(View) instead. So your findViewsById() would be,
public View[] findViewsById(int id) {
View[] views = new View[contentViews.length];
for(int i=0; i<contentViews.length; i++) {
views[i] = contentViews[i].findViewById(id);
}
return views;
}
Your activity should look like the following,
private View[] contentViews;
#Override
public void onCreate(Bundle si) {
super.onCreate(si);
populateContentViews();
setContentView(contentViews[x]);
...
}
Of course you can.
Just do it in recursion:
For each view check its ID, and do it for its children.
That's it.
After all, that's almost what findViewById does. It searches in the view hierarchy like a recursion, till it finds it.
I essentially have a custom IdlingResource that takes a View a constructor argument. I can't find anywhere that really talks about how to implement it.
I'm trying to use this answer: https://stackoverflow.com/a/32763454/1193321
As you can see, it takes a ViewPager, but when I'm registering the IdlingResource in my test class, I'm not sure how I can get my view.
I've tried findViewById() and I've tried getting the currently running activity and then calling findViewById() on that, with no luck.
Anyone know what to do in this scenario?
Figured it out. To get the view to pass into an idling resource, all you have to do is take the member variable of your ActivityTestRule
For example:
#Rule
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(
MainActivity.class);
and then just call getActivity().findViewById(R.id.viewId)
So the end result is:
activityTestRule.getActivity().findViewById(R.id.viewId);
The accepted answer works as long as a test is running in the same activity. However, if the test navigates to another activity activityTestRule.getActivity() will return the wrong activity (the first one). To address this, one can create a helper method returning an actual activity:
public Activity getCurrentActivity() {
final Activity[] currentActivity = new Activity[1];
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
Collection<Activity> allActivities = ActivityLifecycleMonitorRegistry.getInstance()
.getActivitiesInStage(Stage.RESUMED);
if (!allActivities.isEmpty()) {
currentActivity[0] = allActivities.iterator().next();
}
}
});
return currentActivity[0];
}
And then it could be used as the following:
Activity currentActivity = getCurrentActivity();
if (currentActivity != null) {
currentActivity.findViewById(R.id.viewId);
}
If you are using ActivityScenarioRule from androidx.test.ext.junit.rules (since ActivityTestRule "will be deprecated and eventually removed from library in the future"), you can get your Activity instance and call findViewById method:
import androidx.test.ext.junit.rules.activityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
#RunWith(AndroidJUnit4::class) {
#get: Rule
var testRule = activityScenarioRule<MainActivity>()
#Test
fun mainTestCase() {
testRule.scenario.onActivity { activity ->
val view = activity.findViewById<YourView>(R.id.view)
}
}
}
I haven't already used IdilingResources in Espresso, but did you saw these articles:
Espresso: Custom Idling Resource by Chiuki
Wait for it...a deep dive into Espresso's Idling Resources
Also please check official Android Docs: Idling Resources (reference)
To answer your question,
the best way to do it is passing in an instance of one of the Views into the class's constructor. Check: Calling findViewById() from outside an activity
another way is getting view by context. Check android - How to get view from context?
Here's an exmple taken from a link above:
Starting with a context, the root view of the
associated activity can be had by
View rootView = ((Activity)_context).Window.DecorView.FindViewById(Android.Resource.Id.Content);
In Raw Android it'd look something like:
View rootView = ((Activity)mContext).getWindow().getDecorView().findViewById(android.R.id.content)
Then simply call the findViewById on this
View v = rootView.findViewById(R.id.your_view_id);
This might be also useful: How to call getResources() from a class which has no context?
Hope it help
Hello everyone.
I've posted a basic diagram of my Android project above. It's pretty sad but that's what 5 minutes in paint get you.
Anyway, I'll walk you through it. I have xml with a series of imageViews which have onClickListeners in my board.Java class. If one of the imageViews are clicked on, an instance of pawn.java is instantiated, I pass the context to the instantiated pawn object, then call its possibleMoves() method.
At the end of this method I generate a list of int's which happen to be the id's of the imageViews. the final portion of possibleMoves() is the following:
for (String s : chunks) {
String possibleSquare = "s" + s.substring(2, 4);
Toast.makeText(boardContext, possibleSquare, Toast.LENGTH_SHORT).show();
int id = boardContext.getResources().getIdentifier(possibleSquare, "id", boardContext.getPackageName());
System.out.println(id);
ImageView backgroundImg = (ImageView) findViewById(id);
backgroundImg.setBackgroundColor(Color.rgb(255, 255, 255));
}
return list;
The issue I'm having is that AndroidStudio says my findViewById(id) cannot be resolved. I've tried putting the context boardContext (the context I pass to my instantiated pawn object) in front of the findViewById, and I've tried using findViewById(R.id.id).
Suggestions?
findViewById(int id) are functions for View objects - here.. so you can not call it on nothing or any object. When you have reference to an Activity and you call findViewById(int id) it pulls the activity's contentView and calls it on it..
so your to your solution, Inflate the View containing your ImageView or get reference to your activity or if your context that you are passing is an Activity as context then you can cast your activity to the context and call your prefered method
I would like to make a function that automaticly cast my findViewById-View-from reference.
Can i achive this somehow?
private View getReferenceForView(View view, int resId)
{
view = (view.getClass())findViewById(resId);
return view;
}
view.getClass() is not accepted there, but i would like to achive something like this in call:
myView = getReferenceForView(myView, R.drawable.someresid);
So i can get reference for my views without the annyoing casting part.
The only way to use the approach you want is to use reflections instanceof. But this leads in a huge if-else block for every available View in Android.
You would have something like the following:
private View getReferenceForView(View view, int resId)
{
if(view instanceof TextView)
view = view.findViewById(resId);
else if(view instanceof EditText)
// and so on..
return view;
}
I don't know your exact approach but I think this isn't worth the effort.