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 :)
Related
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 want to get First visible child view from android scrollview, on each scroll change event.
Like, when we scroll down, we get all the upcoming view id or reference that's just being visible on screen. How?
I got it on my own.. Here is my code:
Here, we need to create our custom callback listener. Inside its onScrollChanged(), We get int t which is scroll's Y position. Extra, we need child Row height and then just divide that t by rowHeight. Done. We can use getChildAt() further.
scrollView.setOnScrollViewListener(new OnScrollViewListener() {
#Override
public void onScrollChanged(ScrollViewEx v, int l, int t, int oldl,int oldt) {
int rowHeight = rowView.getHeight();
int firstPos = t / rowHeight;
scrollMainChildLL = (LinearLayout) v.getChildAt(0);
gotTxtLL = (LinearLayout) scrollMainChildLL.getChildAt(firstPos);
}
}
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 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.
When I enlarge the size of the content of a scrollview, the scrollview takes a while to get to "know" this size change of it's child. How can I order the ScrollView to check it's child immediately?
I have an ImageView in a LinearLayout in a ScrollView.
In my ScaleListener.onScale, I change the size of my LinearLayout. I then try to order a scroll on the scrollview. In the ScaleListener.onScale:
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imageView.getLayoutParams();
params.width = (int) (startX * scaleFactor);
params.height = (int) (startY * scaleFactor);
imageView.setLayoutParams(params);
(...)
scrollView.scrollBy(scrollX, scrollY);
However, no scrolling occurs when in the situation before the scaling scrolling was not possible because the view was too small to scroll. After the setLayoutParams, the view should be larger, but no scrolling occurs because the scrollview thinks the child is still small.
When a fes ms later the onScroll is called again, it does scroll fine, it somehow found out that the child is larger and scrollable.
How can I notify the scrollview immediately, that the child's size has changed? So that scrollBy will work right after setLayoutParams on it's child?
I found a solution after trying just about every onXXX() method. onLayout can be used. You can plan the scroll and do it later in onLayout().
Extend your scrollview, and add:
private int onLayoutScrollByX = 0;
private int onLayoutScrollByY = 0;
public void planScrollBy(int x, int y) {
onLayoutScrollByX += x;
onLayoutScrollByY += y;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
doPlannedScroll();
}
public void doPlannedScroll() {
if (onLayoutScrollByX != 0 || onLayoutScrollByY != 0) {
scrollBy(onLayoutScrollByX, onLayoutScrollByY);
onLayoutScrollByX = 0;
onLayoutScrollByY = 0;
}
}
Now, to use this in your code, instead of scrollBy(x,y) use planScrollBy(x,y). It will do the scroll at a time when the new size of the child is "known", but not displayed on screen yet.
When you use a horizontal or vertical scrollview, of course you can only scroll one way, so you will have to change this code it a bit (or not, but it will ignore the scroll on the other axis). I used a TwoDScrollView, you can find it on the web.
You can call:
scrollView.updateViewLayout(childView, childLayout)