Android ViewFlipper measures of undisplayed child - android

I have a ViewFlipper on my main Activity's View. At onCreate I instante Views which are added to ViewFlipper. After that I set displayed child to first one. And when a button is clicked I switch ViewFlipper's display child to second view. Right after calling viewFlipper.setDisplayedChild(1) I need to do some calculations and instantate some objects which are based on width and height of displayed child.
Main problem here is that at first time (second = 1) child is displayed measurement of view is not done yet. So my width and height are 0. If I go back (setDisplayedChild(0)) and than goes back to second child it is ok (width and height are correct).
I have done some research about that behavior of views and found out that there is a method [onMeasure](http://developer.android.com/reference/android/view/View.html#onMeasure(int, int)) which can be overrided and everything can be done here. OK that how it should be. Actually it is but problem is that onMeasure is called 4 times on each view switch. And my findings was that at first and third call width and height are full screen sized. The second and fourth call are proper width and height. Because I have to instantate new objects at that point it is unwise to do it in onMeasure.
Is there any other, proper way of doing it?
Is it possible to force measurement?
Do I really need to show view on screen for measurements?
Regards
Zmeda

Your init-action (based on width and height of displayed child) should be invoked after measuring of ViewFlipper's children, you can achieve that using method post, e.g.:
viewFlipper.setDisplayedChild(1);
viewFlipper.post(new Runnable() {
#Override
public void run() {
Log.d("test", "w: " + viewFlipper.getCurrentView().getWidth());// not 0
//do some calculations and instantate some objects
}
});

Related

How to use View.layout() method to change view size?

I have problems doing a small game which adds a lot of views in a ConstraintLayout (I already tested with FrameLayout, RelativeLayout and LinearLayout. First two with same result and Linear with very rare behaviour) and changes the size and position of the views.
Each game loop (33ms) some of the views are changing it's size and position, so I do this on the LayoutParams variable applied on the View on each loop with the new size.
params.width = realWidth;
params.height = realHeight;
and I do this for the position:
view.setX(realX);
view.setY(realY);
The problem is that the change is not reflected if I didn't call view.requestLayout() and that is a huge problem because requestLayout() is repaiting the parent layout and all its childrens, slowing down the game.
How can the size changes of a view be reflected without calling requestLayout? I read that you can achieve that with view.layout(). So I changed my code with this:
view.layout((int)realX, (int)realY, (int)realX+realWidth, (int)realY+realHeight);
The problem is that it works without calling requestLayout() but the view has a very rare behaviour using layout(), and when I add more views, the views become some milliseconds invisible and appear on the left top corner, after that they appear in the correct position, but suddenly they become invisible again and again and again etc in a very rare behaviour loop.
ConstraintLayout is slow, particularly if it contains many Views and much slower if it contains nested ConstraintLayouts.
Because of you are manually setting the position for your Views, you can use a different ViewGroup than ConstraintLayouts and set the absolute position with setX(), setY(), setTop(), etc.

Refreshing custom view layout position

I have to implement slidable menu in my app. User should be able to show/hide it by tapping on it and move left/right.
To implement this, I`ve created custom SlidableFrameLayout that extends FrameLayout.
By overriding onTouchEvent method I calculate slide position and call
private void setLeftLayout(int left) {
layout(left, getTop(), getRight(), getBottom());
}
to change position for SlidableFrameLayout. Everything works fine, but when I keyboard shows (after focusing EditText), SlidableFrameLayout changes its left value to 0, so if menu was closed, it becomes opened. The same thing happens when I hide the keyboard (generally, it appears in all actions that prevents calling layout methods, I think).
I can not invent how to fix it. Could you help me? If any additional info is required, I`ll attach it. Thanks
I think your issue is related to calling layout directly. When the container view changes size as a result of the keyboard being shown/hidden onMeasure/onLayout will be called with the view's default bounds. In your case I'm guessing the left bound is 0, so layout is being called with 0 for left every time your window resizes.
Instead you probably want to use something like setTranslationX or scrollTo ..
Good luck!
As a result, I changed my logic:
private void setLeftLayout(int left) {
FrameLayout.LayoutParams params = getFrameLayoutParams();
params.leftMargin = left;
params.rightMargin = -left;
requestLayout();
}
In my case, view is a parent of FrameLayout, so I haven`t added any conditions in 1st line of the method. This method works pretty fine.

Parent view draw child view efficient

For example, top level LinearLayout view has 300 child view. But device screen dimension only show 11 child view once. How android compute how many child views can show once? How a view know that it will be draw?
Edited
In my work, one case like this:
An parent LinearLayout view may be has hundreds child view. In order to better performance , my solution like this:like lazy load.
List list = new ArrayList();//contain entity object that use construct View object
Default load 5 child view.
Parent LinearLayout view last child view is custom Loading View, I have override it`s onDraw() method. If loading View is draw, that means i need get next 5 child view(get next 5 object from list,and create correspond view).
I want to know how android framework handle this case?
Have u used scroll bar inside the top level LinearLayout view and add child view on that layout that's simple...
An parent LinearLayout view may be has hundreds child view. In order
to better performance , my solution like this:like lazy load.
LinearLayout with(possible) hundreds of child views kind of contradicts better performance. I think what you're looking for is a ListView with an endless adapter(a simple google search will show how to implement it, not something that difficult). This adapter will start loading views(with a loading view showing while the new content loads) as soon as you get to the last loaded element.
If you still want to use a LinearLayout:
If you just want to make the LinearLayout fill the content of the screen when it's first laid out you could post a Runnable on one of your views in the onCreate method (if this is where you'll first populate the LinearLayout). In that Runnable find the height of the LinearLayout and compare it with the combined height of its currently present children. If the combined child height is smaller then the LinearLayout height then add more views to compensate.
If the LinearLayout is in a ScrollView and you want to add additional children when the loading view becomes visible then monitor the scrolling of the ScrollView and when the loading view becomes visible add new children. Seeing when the loading view becomes visible would be done by checking how much the user has scrolled compared with the combined height of the currently present children of the LinearLayout.
Initial response:
Your question is a bit ambiguous regarding what you want to know. If you have a specific problem you should start with that.
For example, top level LinearLayout view has 300 child view. But
device screen dimension only show 11 child view once.
Please don't get yourself in a scenario like this. That number of views is to big an will result in poor performance or even the app crashing if you run out of memory(as all those views will be kept in memory).
How android compute how many child views can show once?
Each View and ViewGroup has the onMeasure method to measure itself and its children if available. The LinearLayout will have its onMeasure method called and in this method it will measure its children(with the measure method) giving them some suggestions on how big should they be(the LinearLayout receives some suggestions on how big it should be from its parent). If you want to see how this is done have a look at the source code of the LinearLayout.
How a view know that it will be draw?
I don't understand what you want to know. To draw the view on the screen its onDraw method will be called.

How do you find the bottom scrollable position in a ScrollView?

In an android scrollView, how do you find the lowest position in the scrollview so you can then use the scrollTo(x,y) method to scroll right to the bottom. I need the actual numeric value. Using the getHeight() method does not ever return the right value. The scrollbar will sometimes scroll to the end, and sometimes not reach it. There is a linearlayout with a textview in the scrollview. There has to be something that I am missing?
If you want to just scroll to the end, you should be able to just use fullScroll(ScrollView.FOCUS_DOWN). If you need a particularly numerical value based on the height of the scroll view, you will have to subclass your scroll view and override onSizeChanged, which will give you the actual numerical height. Keep in mind onSizeChanged will only be called after onResume, and will not necessarily be called every time your activity resumes.
Part of the reason why you sometimes scroll to the end and sometimes don't is probably because of a race condition. Sometimes your scroll happens before other important things (like populating the view) have happened, so it doesn't appear to do anything.
Try posting your calls to your scroll view's handler:
yourScrollView.post(new Runnable(){
#Override
public void run(){
yourScrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
};
Sometimes even adding a short delay can help:
yourScrollView.postDelayed(new Runnable(){
#Override
public void run(){
yourScrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
}, 200);
Thanks for the response. I found a quick hack if anyone is interested.
sView.fullScroll(View.FOCUS_DOWN);
sView.fullScroll(View.FOCUS_DOWN);
y = sView.getScrollY();
sView.fullScroll(View.FOCUS_UP);
This will jump down to the bottom of the scrollable, collect y, then jump up again. It happens so fast it is not visible and it will get you the bottom value of y every time. You have to call focus down twice or else y will return 0.

Threshold for showing View in Android

I have a UI layout that's comprised of a single outer layout that contains three internal layouts. The internal layouts are essentially a header, body and footer.
I would like to cause the top, header view to become completely hidden if it's forced to shrink past a certain threshold. It contains a logo image, and if it shrinks past a certain point, I'd rather just hide it completely.
What's the best way to do this? Is there a way to accomplish this statically in a layout xml? If not, do I need to subclass the View and listen for resizes? Is there another way?
Subclass your View an override the onLayout or onMeasure methods. That is when the View itself decides its width and height. After onMeasure is completed, you can call this.getMeasuredHeight() and check if its below your threshold. If it is, just hide it.
I don't think you can do it in the XML, but whenever anything happens that could shrink it (you might need to use an onTouchListener() if it's shrunk by the user's finger), you can call getHeight(), and if it's less than a certain value call setVisibility(View.GONE) on it.

Categories

Resources