I want to fade from one view to another on in a ViewGroup.
At the moment I'm doing the transition using setAlpha, but the problem is that only one view is being rendered, the one that was on top and is fading out.
Is the view-array inside ViewGroup an order by z-axis?
Is only the top view being rendered?
My layout method looks like this:
#Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
L.debug("laying out {} children", this.getChildCount());
for (int i = 0; i < this.getChildCount(); i++) {
L.debug("layout out {}", i);
View view = this.getChildAt(0);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
}
}
Why don't you want to use ViewSwitcher? It does exactly what you want. Here is an example.
Is the view-array inside ViewGroup an order by z-axis?
There is no such thing like Z-order in android. Views are drawn in oder they were added to ViewGroup. First added draws first.
Is only the top view being rendered
No, android will draw all views in visible rect even if they are totally overlaped by others.
I think you should fix this place this.getChildAt(0) and layout all childrens in your ViewGroup.
Related
I have two views A and B. View B is completely covered view A which means the bounding rect of view B is more than bounding rect of view A.
The best example I can give is, I have a fixed bottom tabs layout and a RecyclerView with multiple linear layouts. When I scroll, one of the linear layout will be behind the bottom tabs layout.
So, How can I programatically check If view A is completely covered by other views (other views might not be known upfront)?
Is there any possible way to identify this?
Update:
I have tried the solution mentioned here. But it didn't solve my problem. In my case, the view bounds are exactly matching and I want which view is on top.
After lot of struggle, I have found a way to identify if view is overlapped by other views in the following way.
AccessibilityNodeInfo nodeInfo = AccessibilityNodeInfo.obtain();
viewA.onInitializeAccessibilityNodeInfo(nodeInfo);
if (!nodeInfo.isVisibleToUser()) {
// View is not visible to user. This also validates if viewA is overlapped by other views
}
nodeInfo.recycle();
Use the following method it will help you to find view overlapping:-
private boolean isYourViewOverlapping(View firstView, View secondView) {
int[] firstPosition = new int[2];
int[] secondPosition = new int[2];
firstView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
firstView.getLocationOnScreen(firstPosition);
secondView.getLocationOnScreen(secondPosition);
int r = firstView.getMeasuredWidth() + firstPosition[0];
int l = secondPosition[0];
return r >= l && (r != 0 && l != 0);
}
In a special android application, I want to remove all child views from their parents if entire or a part of them was overflowed of their parents bounds (on window focus changed).
I have tried to write manual calculations on children and parent widths but I am looking for an object oriented solution to be applicable on all kinds of views.
This would probably the easiest by just extending the ViewGroup you are using and removing the views after layouting them. (ViewGroups include LinearLayout, RelativeLayout, ...)
By overwriting onLayout you could iterate over your children and remove any views with bounds not within of their parent.
Things to note: This will probably trigger another layout call, so be sure to properly handle things.
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// call super to layout children and have their bounds set
super.onLayout(changed, left, top, right, bottom);
// Iterate over all children
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getLeft() < left
// ... add top / bottom
|| child.getRight() > right) {
removeView(child);
}
}
}
And if you want to handle things without extending the ViewGroup you can always handle things by using the same principle after the view got layouted.
I have spent the whole day debugging various ways to add custom ViewGroup into another custom ViewGroup and nearly went crazy because none of them works, and there is no official documentation or sample that shows how it can be done...
Basically, I have 2 custom ViewGroup:
HorizontalDockView extends ViewGroup
GameEntryView extends FrameLayout
HorizontalDockView overrides onDraw, onMeasure, etc and everything is called normally and works perfectly.
However, when I create GameEntryView from inside HorizontalDockView's constructor and call addView(gameEntryView), the gameEntryView will never ever show regardless of the layoutParams, addView called from whatever thread, or however I call, load, and setContentView on the parent HorizontalDockView. If I list through the horizontalDockView.getChildAt(); all the gameEntryView objects are still there.
Hopeless, I try to debug through GameEntryView's onDraw, onMeasure, dispatchDraw methods and realized none of them actually get called! No.. not even once!
Do I need to iterate through all the child view in the parent (HorizontalDockView's) on* call and call the children's on* explicitly? I was just calling super.on*() on the parent.
I did call setWillNotDraw( false ); on both the parent and the child class.
How do I get the child to show up inside the parent's view? simple sample or existing small open source project is highly appreciated!
Thank you very much!
Did you overwrite onLayout? When Android lays out your ViewGroup, your ViewGroup is responsible for laying out the children.
This code is from a custom ViewGroup that lays out all children on top of each other:
#Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
int count = this.getChildCount();
for (int i = 0; i < count; i++) {
View child = this.getChildAt(i);
child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
}
}
For completeness, the onMeasure override:
#Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth, parentHeight);
int count = this.getChildCount();
for (int i = 0; i < count; i++) {
View child = this.getChildAt(i);
this.measureChild(
child,
MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(parentHeight, MeasureSpec.EXACTLY));
}
}
I have several LinearLayouts that get filled with downloaded images or text within a ScrollView. The LinearLayouts have a LayoutAnimation applied to them, so each one "slides" into place when drawn. Is there a way to force the offscreen LinearLayouts to draw so that by the time the user scrolls to them, the animation has already completed? I've tried measuring each view like so: (container is the ViewGroup)
int measuredWidth = View.MeasureSpec.makeMeasureSpec(LayoutParams.FILL_PARENT, View.MeasureSpec.AT_MOST);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, View.MeasureSpec.UNSPECIFIED);
container.measure(measuredWidth, measuredHeight);
container.layout(0, 0, container.getMeasuredWidth(), container.getMeasuredHeight());
container.requestLayout();
But they still won't draw until they appear on screen during scrolling (which normally is fine but the animation makes it.. er, not fine)
If you don't want to run the animation why don't you simply remove the animation? The framework will apply the animation because you tells it to.
Also note that none of your code causes a redraw. To draw you need to call invalidate() or draw().
For any future readers, here's what I ended up doing: I subclassed LinearLayout and overrode onLayout to only apply animation if the layout is currently on screen at the moment it is populated:
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
super.onLayout(changed, left, top, right, bottom);
// only animate if viewgroup is currently on screen
int[] xy = new int[2];
this.getLocationOnScreen(xy);
int yPos = xy[1];
if (yPos < availableScreenHeight && bottom > 200)
{
Animation slide_down = AnimationUtils.loadAnimation(getContext(), R.anim.container_slide_down);
LayoutAnimationController controller = new LayoutAnimationController(slide_down, 0.25f);
this.setLayoutAnimation(controller);
}
}
This actually saves some cycles since I'm not applying animation across the board then removing it from views that don't need it. (BTW "availableScreenHeight" is just that, and "200" is simply a threshold that I know a populated view will never be smaller than. Your case may vary.)
Can anyone give me a tip for how to get the position of a view what is a child of an AbsoluteLayout? I want to do this for drag and drop the selected view.
Thank you!
AbsoluteLayout is deprecated, so probably you would have to provide your own drag&drop layout by extending ViewGroup. In general, layout it is responsible for positioning children widgets. This is done in onLayout() method which you would have to override. It will be probably something like this:
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
for(int i=0; i<count; i++){
final View child = getChildAt(i);
if(GONE != child.getVisibility()){
//position child
child.layout(left, top, right, bottom);
}
}
}
So, by implementing your own DragAndDropLayout - you know the position of your children.
But, maybe there is simplier solution.
Regards!
To know where a child is in its parent, simply call getLeft() and getTop(). Also, do not use AbsoluteLayout :)