What is the difference between addView and addViewInLayout - android

I have seen some widgets using addView and sometimes addViewInLayout.
What is the difference between them?
What will happen if I replace one with the other?
Should I keep a flag during layout and use "addViewInLayout" or "addView" accordingly?
Thanks.
BR,
Henry
ps. add more tags: removeview, removeviewinlayout

Its generally a bad idea to call addView inside onLayout because addView internally triggers a requestLayout which eventually will call onLayout. So you end up triggering a layout while you are in the middle of a layout.
addViewInLayout is a "safer" version of the addView in the case you really have to add a new view in onLayout. It basically doesn't trigger a layout pass (doesn't call requestLayout internally).
See this video (by android engineer) for more detail: http://www.youtube.com/watch?v=HbAeTGoKG6k

addViewInLayout
Adds a view during layout. This is useful if in your onLayout() method, you need to add more views (as does the list view for example). If index is negative, it means put it at the end of the list.
addView
Assign the passed LayoutParams to the passed View and add the view to the window.
*Note that addView is implemented by ViewManager, an Interface to let you add and remove child views to an Activity, so you will be able to add views to ViewGroup at run time (DYNAMICALLY). Also note that addViewInLayout is a protected method of ViewGroup so if you are doing to create a custom view group you can call addViewInLayout() in onLayout() method.
For more see this

for example: we have a Layout (mLayout) and you want to add 2 views (view1, view2) into this layout.so there are 2 ways (the same)
case1: simply you use following command
mLayout.addView(view1); //onLayout() will be called first time
mLayout.addView(view2); //onLayout() will be called second time after the first time.
in this case, you don't care function onLayout(). it is simple source code.
case2: complicate but better performance
//do something to <global variable>
bCheck = true; //check it in fuction onLayout()
requestLayout(); //use this function to call onLayout() function for only one time
//in onLayout() function of mLayout, you use addViewInLayout()
//addViewInLayout() dont call onLayout() function, so you can add 2 views with only one time to call onLayout()
//onLayout() is abstract function, so mLayout is a instant of subclass of ViewGroup (ex: RelativeLayout, LinearLayout....)
#Override
onLayout(boolean changed, int l, int t, int r, int b)
if(bCheck == true){
v.addViewInLayout(view1); //add view1 to mLayout
v.addViewInLayout(view1); //add view2 to mLayout
bCheck = false;
}
}
});
I have no time to test it. anyone can help me make it more clear.

Related

getViewTreeObserver for 2 views

Haven't found something to understand how to use it correctly.
I need to measure 2 views.
For first view i use this:
viewPager.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
//my measure code
viewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
So what should i do for second view: i should use another same block of code, but for second view or can i put second measurement inside viewpager's measurements?
Added: logically it can be different cases:
One view inside another view.
Two views near each other in same parent (viewObserver on first view).
Two views near each other in same parent (viewObserver on parent).

Get the position of a view just after an addView()

Everything is in the title. I need to add the view at some point in my relativeLayout but not necessary at the OnCreate method. What I want to do is adding a view when the user click on the RelativeLayout, no problem for that. But I need to know the position of this view as soon as possible after I used addView method. Currently I'm using postDelayed but I need to put a high value to be sure that it is displayed before taking the position of the view. I tried using post but didn't work very well so that's why i use a delayed value. I also tried something with treeObserver some time ago but maybe i used it wrong I don't know because it did not work.
Edit:
Here I create the layout param.
RelativeLayout.LayoutParams laoutparam = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT );
laoutparam.addRule(RelativeLayout.CENTER_IN_PARENT);
Here I create my custom view and add the layoutparam to it:
Button button = (Button)findViewById(R.id.lol);
CustView view = new Bubble(getApplicationContext(), "Press this button", button);
bubble.setLayoutParams(laoutparam);
And then in the constructor of my custom RelativeLayout I do an addView(view).
Thanks for your help.
I hope this helps you with getting view location: https://www.tutorialspoint.com/how-to-get-the-absolute-coordinates-of-a-view-in-android
Example:
int loc[]=new int[2];
yourView.getLocationOnScreen(loc);
int x=loc[0];
int y=loc[1];

Dynamically change properties of View objects

On my activity's creation I have set an AlphaAnimation in order to perform some visual effects. Now I have set a LayoutAnimationListener and overriden the onAnimationEnd() method. The Animation is executed correctly and the callback to onAnimationEnd() is working as well. Within the onAnimationEnd() method I want to perform another animation on two child objects of the Activity's layout. These are two EditTexts that are defined in XML with the property android:visibility="gone". For starters, what I want to do is to have them set as VISIBLE.
I've tried getting a reference from their parent, change their setVisibility(View.VISIBLE); and in the end invalidate the parent view.
This attempt does not seem to work. You will find the code attached below:
#Override
public void onAnimationEnd(Animation animation) {
Log.d(TAG, "onAnimationEnd()");
// TODO move icon up, make edittext's appear.
RelativeLayout layout = (RelativeLayout) View.inflate(
getApplicationContext(), R.layout.splash_dialog_layout,
null);
LinearLayout linear = (LinearLayout) layout.getChildAt(0);
Log.d(TAG, "Children" + linear.getChildCount());
email = (EditText) linear.findViewById(R.id.splash_Email);
email.setVisibility(View.VISIBLE);
pass = (EditText) linear.findViewById(R.id.splash_password);
pass.setVisibility(View.VISIBLE);
linear.invalidate();
layout.invalidate();
Splash_Activity.layout.invalidate();
}
};
I've tried to removeAllViews from a parent and add them one by one and invalidate again but that doesn't seem to work either.
There is probably a misunderstanding on my behalf as to how view inflation operates, shouldn't this work?
Thanks for your time.
Inflating a layout creates a new view hierarchy, which means the views you're obtaining are actually different from the ones displayed on screen even though they have the same IDs.
You can obtain on-screen views in several ways, but the easiest would probably be to query the containing Activity.
Activity.this.findViewById(R.id.splash_Email);

RelativeLayout check runtime if is removed or not

In an activity I am changing one of the ViewGroup content runtime: buttons action, other events.
At a specific case I need to check if a child is in this layout or not ( in this case the child is another RelativeLayout, which hold other views)
How can I check runtime, programmatically if child_1_RelativeLayout is there or is already removed from view tree, his parent is parentRelativeLayout
The getParent() is usefully? - not much explanation how to use it, thanks.
In case you have stored your views you can use getParent() to check if view is a direct child for other view. After removing view its parent field will be cleared. For example:
ViewGroup parent = ...;
View child = ...;
assert(child.getParent() == parent); // <-- true
parent.removeView(child);
assert(child.getParent() == parent); // <-- false
Not really sure if I understand your question correctly, but:
when you add the relative layout, be sure to first give it an id (either in your layout.xml file, or from code)
to check existence of the relative layout within the ViewGroup, use ViewGroup's findViewById() method (inherited from View) and pass it the id you've given to the relative layout
if it returns null, the relative layout is not there, otherwise findViewById() will find it
So in short, findViewById() is not only defined for an Activity, but you can call this on any view you would like to use as a starting point for your search.

Layout a view after resizing

I'm creating a grid that displays values that change very often. Because of this, I'm using a TextView that autoresizes when its content changes (Auto Scale TextView Text to Fit within Bounds). The resize takes place, but the view doesn't layout properly
The thing is, when I examine the activity with HierarchyViewer the layout displays as I want.
My guess is that HierarchyViewer invokes requestLayout() or invalidate() on the view, but I've tried that with no success. This code is invoked in the main activity with no effect.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getWindow().getDecorView().requestLayout();
getWindow().getDecorView().invalidate();
}
}, 5000);
I've also tried invalidating the view after resizing.
The TextView has gravity set to Center, and if no resize takes place, it looks ok.
Any hint will be welcome, thanks in advance!
I solved it by overriding onLayout in one of the TextView's parent and using a Handler created in the constructor
public class CellView extends LinearLayout{
public CellView(Context context) {
super(context);
mHandler = new Handler();
View.inflate(context, R.layout.cellview, this);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if(changed){
mHandler.post(new Runnable() {
#Override
public void run() {
requestLayout();
}
});
}
super.onLayout(changed, left, top, right, bottom);
}
I had tried calling requestLayout inside TextView's onLayout, tho it didn't work, I'm not sure why. It might be because the value was updated through an Observer, but the onTextChanged listener should happen in the UI Thread. I hope it serves someone else
The way requestLayout() works is that when called on a view, it will schedule a layout pass on itself and all of it's children. This is desirable whenever a view has shifted or resized do to margin, padding, or content changes.
The documentation on the method getDecorView() isn't very clear on what exactly it gives you. However, per the documentation on the website:
Note that calling this function for the first time "locks in" various window characteristics as described in setContentView(View, android.view.ViewGroup.LayoutParams).
This leaves me to believe that there's something special about the view that getDecorView() retrieves. What you are probably doing is making the layout of the view permanent thus never changing when you make a requestLayout() pass.
This is apparently the proper way to get the root view of your entire activity.
However, for efficiency reasons, I recommend calling requestLayout() on the lowest child you possibly can. Like I said before, it schedules a layout pass on a view and it's children. If you do a layout pass on the top-most view, you're essientially rebuilding everything which includes the views that stay in place.
You probably need to run the timer code in the UI thread using runOnUiThread as explained here.

Categories

Resources