I have a custom ViewGroup which has two children, a ViewPager and another subclass of ViewPager.
When I instantiate it from code, it displays fine. However, when doing so from XML, the second child was not showing. I confirmed by add other views above and below the custom ViewGroup from XML and it turns out that the view was vertically offsetting by some amount which led to the second child being truncated.
The measuring seemed fine since I got the correct gap between t and b in the onLayout(). So I tried the following in my onLayout() before calling layout() on the children.
b = b - t;
t = 0;
Voila.... its displays perfectly, which doesn't really make sense since there is a view above this one which means t being zero should overwrite it (or maybe its relative, I could be wrong).
Anyways, what bugging me is why the arguments to the onLayout() were obviously offsetting the view ?
Related
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.
I'm working on a custom ViewGroup.
This ViewGroup has a bunch of children. I need to animate a few and change their position. I understand that Android animations move just the bitmap and not the real object. I've been trying to MOVE them by following various resources but have failed.
What I'm doing with ViewGroup so far:
Measure children and the ViewGroup
Position children in onLayout
What I'm trying to do further
Use a custom animation to move a small subset of the children. I'm using a custom Animation object because I need to move a bunch of Views and I'm applying translationX on all of them together. The other option that I know is to start a separate Animation on all of them and the thought of which makes me think it's gonna be unoptimized.
Problem
Views animate fine, but their real position remains unchanged. So the next time I'm trying to do the same kind of animation, but on the new co-ordinates, it doesn't work. Because, their positions haven't updated.
What did I try
Use onAnimationEnd to layout each of the children to the new left, top, right and bottom position. All views vanished
On onAnimationEnd, reset translationX to zero and then start re-positioning the views. No effect of calling view.setTranslationX(0f)
Can someone please help me with the correct way of doing this? Thanks
when animating call layout() on your child Views
I am trying to render a RemoteViews instance onto a Canvas, like I do with a regular View. I use
RemoteViews.apply(context, null)
and it returns a FrameLayout with all the views nested and properly measured (location and size is correct,) but after using .draw on the returned view, it renders all elements with no values -- TextViews are empty, AnalogClock is reset at 00:00 and so on.
Any ideas? I'm lost :(
Not sure if the question is still actual. Nevertheless here is my experience with RemoveViews. It appears you cannot just call draw() on the returned view. You have to add this view to a parent container to make it a part of global view hierarchy. For instance, you have an Activity with a single FrameLayout in it. Your code will look like this.
FrameLayout parent = findViewById(R.id.container);
View view = RemoteViews.apply(getActivity(), parent);
parent.addView(view);
Now you should be able to see tests. If you set listeners, they will work properly too.
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.
I'm trying to convert the RealViewSwitcher based on the work from Marc Reichelt into one that is backed up with a ListAdapter. A horisontally scrollable ViewGroup that contains multiple views, where one is visible at a time.
My current solution adds at the most 3 views to the ViewGroup at a time. One (in the middle) which is visible and two buffered views, one on each side. When a user scrolls, say to the right, the left-most View is removed and a new View is added to the right. In order for the ViewGroup to be scrollable both to the left and right I need to always focus on the View in the middle. So, when a View is being switched, I arrange the Views correctly and sets focus on the View in the middle. The issue with this approach is that it suffers with a flickering effect when the Views are arranged. Let me illustrate the issue with a picture I drew:
A, B and C are three different views in my ViewGroup (the ListAdapter backing up the ViewGroup contains of more elements though, but only three are loaded at a time). The larger rectangle represents where focus is at the moment. I scroll to the left and at (3) I snap to the destination which is the left-most View. Then I re-arrange the view. I.e. Add a new view X to the left and remove View C to the right, placing A in the middle. Finally I center on the View in the middle (A) which was the one I scrolled to from the beginning.
So, when I do the last re-arranging of Views and center on A in the middle, the content of the View which was previously in the middle (B in this case) flashes a few milliseconds causing a flicker effect which is uncalled-for. Any ideas of how I can go around that?
Problem solved. The issue seems to be related to changing the childs in a ViewGroup and then call the scrollTo method. If I instead use a Scroller to move to the right view/child, the flickering issue disappears.