android - get estimated height of a programmatically created view - android

How to get programmatically created RelativeLayout's height after adding all the views in it (i.e., when it really can be measured)? I programmatically created Buttons that should be children for that RL, set their margins and alignment, added them to the RL, so RL's height can be measured. Ordinary rl.getHeight() returns 0. I used this code:
rl.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int rlHeight=rl.getMeasuredHeight();
And on Nexus 5 (API 23) everything's ok, but on the other device with API 17 (as I remember, 4.2 or something) it throws NPE. What to do?
P.S. OnGlobalLayoutListener and OnPreDrawListener are not ok, because I need the height to be measured before calling setParams(...) and adding the RL to outer layout.

You can use a GlobalLayoutListener or an OnPreDrawListener to programmatically find a views height at runtime. Refer to this answer for an example: https://stackoverflow.com/a/6569243/4898635
Make sure to remove the listener after you have your height however, otherwise it will continuously be called.

Related

setTop alternative for api under 11

I've been searching for an alternative for the android.widget.ImageView.setTop# method in android which would work for api's under 11 or Honeycomb. Is such an alternative even available?
For anything below Honeycomb (API Level 11) you'll have to use setLayoutParams(...).
you can dynamically set the position of view in Android. for example if you have an ImageView in LinearLayout of your xml file.So you can set its position through LayoutParams.But make sure to take LayoutParams according to the layout taken in your xml file.There are different LayoutParams according to the layout taken.
Here is the code to set:
FrameLayout.LayoutParams layoutParams=new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(int left, int top, int right, int bottom);
imageView.setLayoutParams(layoutParams);
From android documentations: doc
Sets the top position of this view relative to its parent. This method is meant to be called by the layout system and should not generally be called otherwise, because the property may be changed at any time by the layout.
This method shouldn't be called directly, mainly because different ViewGroups have different approach to layout which makes this method not consistent (framelayout).
as #nitesh goel suggested, use Margin or padding to set the spacing between a child view and its original position in the ViewGroup. doc
Size, padding and margins
The size of a view is expressed with a width and a height. A view actually possess two >pairs of width and height values.
The first pair is known as measured width and measured height. These dimensions define how big a view wants to be within its parent (see Layout for more details.) The measured dimensions can be obtained by calling getMeasuredWidth() and getMeasuredHeight().
The second pair is simply known as width and height, or sometimes drawing width and drawing height. These dimensions define the actual size of the view on screen, at drawing time and after layout. These values may, but do not have to, be different from the measured width and height. The width and height can be obtained by calling getWidth() and getHeight().
To measure its dimensions, a view takes into account its padding. The padding is expressed in pixels for the left, top, right and bottom parts of the view. Padding can be used to offset the content of the view by a specific amount of pixels. For instance, a left padding of 2 will push the view's content by 2 pixels to the right of the left edge. Padding can be set using the setPadding(int, int, int, int) or setPaddingRelative(int, int, int, int) method and queried by calling getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom(), getPaddingStart(), getPaddingEnd().
Even though a view can define a padding, it does not provide any support for margins. However, view groups provide such a support. Refer to ViewGroup and ViewGroup.MarginLayoutParams for further information.

Measure a layout before adding views in it?

I have a RelativeLayout as root element. There are three LinearLayouts under root element. First and last has fixed height and the middle one takes rest of screen.
There are two ScrollViews inside the middle LinearLayout. I programatically add new views in them. I want to show three item in a scrollview no matter the screen size is.
The problem is, I can't calculate the height of are so I can't divide it by three and get item height required.
I tried to call measure() and getMeasuredHeight() but LinearLayout returned 21 (which I have no idea why) and ScrollViews returned 0. Both LinearLayout and ScrollViews has match_parent attribute.
So how can I get the actual height? I know it is calculated somewhere because I can see it covers the all empty area.
The Good
Don't unless you have a really good reason. This kind of layout won't work for tablets and larger devices (it will look very odd having giant list items) and it is not common behaviour.
The Bad
You said the top and bottom views have a fixed size, and you can get the height of the screen with:
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
// Use getSize on API13+
int displayHeight = display.getHeight();
Then the height of each row is just
int listHeight = displayHeight - (2 * fixedHeight)
int rowHeight = listHeight/3;
This is bad because it will not work in more complex layouts.
The Ugly
In onCreate the size of your views will not yet have been initialised. You need wait until the view has been given a size. There a few ways you could do this:
Use a View.OnLayoutChangeListener (API 11+)
Use a ViewTreeObserver.OnGlobalLayoutListener (API 1+)
Create a custom View class (subclass LinearLayout) and override onSizeChanged

How To Scale A Layout While Keep Its Children Original Scale

Can I Scale A Layout(e.g LinearLayout) from 0.5 to 1.0 while Keeping the size And position of the TextView inside the layout to 1.0 During the whole transformation (the overflow parts should hidden)?
I see That The Scale Animation in IOS Keep the scale of the Children And How Can I Achieve this in Android ?
Plus,On Starting Animation, The Parent Layout of the animated block has already make space for it,But in IOS ,the parent makes room gradually during the animation, does it have an option for me to do the same thing in Android ?
This can be done pretty easily with the Property Animation API.
havent tried it on LinearLayout but if the view children are ordered correctly with their "layout_width" & "layout_height" you can use the ValueAnimator class to scale the parent view via LayoutParams.width & height.
Only setback is API 11 and above.

How can I dynamically set the position of view in Android?

How can I change the position of view through code? Like changing its X, Y position. Is it possible?
For anything below Honeycomb (API Level 11) you'll have to use setLayoutParams(...).
If you can limit your support to Honeycomb and up you can use the setX(...), setY(...), setLeft(...), setTop(...), etc.
Yes, you can dynamically set the position of the view in Android. Likewise, you have an ImageView in LinearLayout of your XML file. So you can set its position through LayoutParams.But make sure to take LayoutParams according to the layout taken in your XML file. There are different LayoutParams according to the layout taken.
Here is the code to set:
LayoutParams layoutParams=new LayoutParams(int width, int height);
layoutParams.setMargins(int left, int top, int right, int bottom);
imageView.setLayoutParams(layoutParams);
There are different valid answers already, but none seems to properly suggest which method(s) to use in which case, except for the corresponding API level restrictions:
If you can wait for a layout cycle and the parent view group supports MarginLayoutParams (or a subclass), set marginLeft / marginTop accordingly.
If you need to change the position immediately and persistently (e.g. for a PopupMenu anchor), additionally call layout(l, t, r, b) with the same coordinates. This preempts what the layout system will confirm later.
For immediate (temporary) changes (such as animations), use setX() / setY() instead. In cases where the parent size doesn't depend on WRAP_CHILDREN, it might be fine to use setX() / setY() exclusively.
Never use setLeft() / setRight() / setBottom() / setTop(), see below.
Background:
The mLeft / mTop / mBottom / mRight fields get filled from the corresponding LayoutParams in layout(). Layout is called implicitly and asynchronously by the Android view layout system. Thus, setting the MarginLayoutParams seems to be the safest and cleanest way to set the position permanently. However, the asynchronous layout lag might be a problem in some cases, e.g. when using a View to render a cursor, and it's supposed to be re-positioned and serve as a PopupMenu anchor at the same time. In this case, calling layout() worked fine for me.
The problems with setLeft() and setTop() are:
Calling them alone is not sufficient -- you also need to call setRight() and setBottom() to avoid stretching or shrinking the view.
The implementation of these methods looks relatively complex (= doing some work to account for the view size changes caused by each of them)
They seem to cause strange issues with input fields: EditText soft numeric keyboard sometimes does not allow digits
setX() and setY() work outside of the layout system, and the corresponding values are treated as an additional offset to the left / top / bottom / right values determined by the layout system, shifting the view accordingly. They seem to have been added for animations (where an immediate effect without going through a layout cycle is required).
There is a library called NineOldAndroids, which allows you to use the Honeycomb animation library all the way down to version one.
This means you can define left, right, translationX/Y with a slightly different interface.
Here is how it works:
ViewHelper.setTranslationX(view, 50f);
You just use the static methods from the ViewHelper class, pass the view and which ever value you want to set it to.
I would recommend using setTranslationX and setTranslationY. I'm only just getting started on this myself, but these seem to be the safest and preferred way of moving a view. I guess it depends a lot on what exactly you're trying to do, but this is working well for me for 2D animation.
You can try to use the following methods, if you're using HoneyComb Sdk(API Level 11).
view.setX(float x);
Parameter x is the visual x position of this view.
view.setY(float y);
Parameter y is the visual y position of this view.
I hope it will be helpful to you. :)
For support to all API levels you can use it like this:
ViewPropertyAnimator.animate(view).translationYBy(-yourY).translationXBy(-yourX).setDuration(0);
Set the left position of this view relative to its parent:
view.setLeft(int leftPosition);
Set the right position of this view relative to its parent:
view.setRight(int rightPosition);
Set the top position of this view relative to its parent:
view.setTop(int topPosition);
Set the bottom position of this view relative to its parent:
view.setBottom(int bottomPositon);
The above methods are used to set the position the view related to its parent.
Use LayoutParams.
If you are using a LinearLayout you have to import android.widget.LinearLayout.LayoutParams, else import the proper version of LayoutParams for the layout you're using, or it will cause a ClassCastException, then:
LayoutParams layoutParams = new LayoutParams(int width, int height);
layoutParams.setMargins(int left, int top, int right, int bottom);
imageView.setLayoutParams(layoutParams);
NB: Note that you can use also imageView.setLeft(int dim), BUT THIS WON'T set the position of the component, it will set only the position of the left border of the component, the rest will remain at the same position.
Use RelativeLayout, place your view in it, get RelativeLayout.LayoutParams object from your view and set margins as you need. Then call requestLayout() on your view. This is the only way I know.
In Kotlin you can do it as below;
view
.animate()
.x(50f)
.y(100f)
.duration = 500L
I found that #Stefan Haustein comes very close to my experience, but not sure 100%. My suggestion is:
setLeft() / setRight() / setBottom() / setTop() won't work sometimes.
If you want to set a position temporarily (e.g for doing animation, not affected a hierachy) when the view was added and shown, just use setX()/ setY() instead. (You might want search more in difference setLeft() and setX())
And note that X, Y seem to be absolute, and it was supported by AbsoluteLayout which now is deprecated. Thus, you feel X, Y is likely not supported any more. And yes, it is, but only partly. It means if your view is added, setX(), setY() will work perfectly; otherwise, when you try to add a view into view group layout (e.g FrameLayout, LinearLayout, RelativeLayout), you must set its LayoutParams with marginLeft, marginTop instead (setX(), setY() in this case won't work sometimes).
Set position of the view by marginLeft and marginTop is an unsynchronized process. So it needs a bit time to update hierarchy. If you use the view straight away after set margin for it, you might get a wrong value.
One thing to keep in mind with positioning is that each view has an index relative to its parent view. So if you have a linear layout with three subviews, the subviews will each have an index: 0, 1, 2 in the above case.
This allows you to add a view to the last position (or the end) in a parent view by doing something like this:
int childCount = parent.getChildCount();
parentView.addView(newView, childCount);
Alternatively you could replace a view using something like the following:
int childIndex = parentView.indexOfChild(childView);
childView.setVisibility(View.GONE);
parentView.addView(newView, childIndex);

How to set fixed size and position of a RelativeLayout?

Android implemented a default layout rule, like measure, layout, etc, I didn't find out there is a method to set such a fixed size. How to get rid of that default layout behavior?
Actually, in my case, every view is supposed to be relative to its parent, and will have a specified size., how could I do?
Thx
Not sure if I correctly understood your issue, but you can specify size of certain View (e.g. RelativeLayout, LinearLayout or certain control). In Properties of your layout view (Layout width, Layout height) you do not need to use only wrap_content or fill_parent. You are also allowed to type size like 40dip.
If you created your View dinamically, then you should set LayoutParams. For example, to define your element size and margins for RelativeLayout (similar for others) you should use something like:
RelativeLayout.LayoutParams adaptLayout = new RelativeLayout.LayoutParams(element_width, element_height);
adaptLayout.setMargins(marginLeft, marginTop, marginRight, marginBottom);
mLinearLayoutForm.setLayoutParams(adaptLayout);

Categories

Resources