Is there a way to dynamically change the position(like a manually translation animation) on a child view thats been defined and places inside onLayout?
i have this onLayout defined here:
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//place topview at the top of the layout by removing the ySpace value defined fro the height
// of this view and dividing the height so that the topView takes nearly half the space
// height of this view container
topView.layout(0, 0, getWidth(), (getHeight() - ySpace) / 2);
}
i want to manually change the y axis position of topView Dynamically .
i was thinking ofabout onDraw but onDraw doesnt that childViews and draws them. Instead it just gives you a blank canvas to manually draw items in it.
Currently implementing a custom ViewGroup that takes x amount of child views and dynamically moves them around. My question is how do i move them around?
Related
I have a custom view which is nested inside of a ScrollView. The idea is that the custom view can be longer than the height of the screen, so when you swipe through the ScrollView you can see all of its contents.
In order to do this I adjust the clip of the custom view's canvas like this:
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.clipRect(mCanvasArea, Region.Op.REPLACE);
}
Where mCanvasArea is a pre-generated RectF which represents the entire area the canvas can draw. I logged it's value # 10308.
However when the app runs, the custom view is unscrollable, it acts as if the visible content represents all of the content in the canvas, but I can see more peeking up from the bottom of the screen.
Here is my XML declaration for the view:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/activity_toolbar"
android:fillViewport="true">
<com.myapp.CustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</ScrollView>
(I had to add fillViewport in order to get the content to show up in the first place)
Is there anything else that needs to be done in order yo make the view scroll?
You will need to specify the height of the custom view, not the canvas. The canvas passed to onDraw reflects the width and height of the view.
Setting the view to wrap_content doesn't mean it will grow whenever you draw outside of its bounds. It will only "wrap" the child views, not the canvas.
To set your view's height programmatically:
getLayoutParams().height = 500;
invalidate();
I'm not sure what you are going for with this exactly so I can't get too much more specific about where you should set the height, but I'd recommend not changing your view's dimensions in onDraw because when you invalidate it will cause another draw and you'll need some funky logic to handle this recursion.
Instead you could determine the height you need when the view is constructed, and then override onMeasure with something like this:
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, calculatedHeight);
}
This would force your custom view into the calculated height.
I have two views, lets say A and B. I want A to be placed above B vertically, but center-aligned with B horizontaly, i.e. I want to achieve this:
I tried:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
viewA.getLayoutParams();
layoutParams.addRule(
RelativeLayout.ABOVE,
viewB.getId()
);
But apparently what it did is placing A vertically above B, but horizontally floating to the left (aligned with X's left)
Please help.
What you have is on the right path, but you need to also add a rule for the horizontal centering: layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
I recognize that this doesn't quite do what you asked in that it is specifying that you center in the parent view horizontally as opposed to specifying that you align the horizontal centers of A and B, but there isn't a direct way to do the latter with a RelativeLayout rule. (There are many indirect ways to do it instead.)
Addition:
Given that your view A is not centered horizontally in the parent, here's a suggestion. I don't know of a great / non-hacky way to do this, but I think that since RelativeLayout rules are applied during the measurement pass, you can use the left (and right) coordinates of view A after measurement is done to set the (public) left and right properties of view B to what they need to be in order to center the view under A.
So for example, if your parent view is a custom extension of View you can override its onMeasure() method, call like:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); // So that mA.left and mA.right first get set...
mB.left = BWIDTH - (mA.left + mA.right) / 2;
mB.right = mB.left + BWIDTH;
/* You probably will need to re-measure (i.e., call super.onMeasure() again here)
* if you need to get views X and Y to the left of view B or if
* if view B exceeds the previously-measured size... */
}
And if not, you can use setOnLayoutChangeListener() on the parent and a callback to achieve the same thing.
I am facing the same problem in this question, but I have difficulty in understanding the exact meaning of the four position parameters in layout(int l, int t, int r, int b). I know they represent left, top, right and bottom respectively relative to parent, but "relative" to where exactly?
For example, if I translate the button down 100 pixel, in order to move the clickable area down 100 pixel should I set
// l t r b
button.layout(0, 100, 0, button.getHeight()+100)
? Does the integer 100 of second parameter mean 100 pixel down relative to the top of parent? Is the fourth parameter means button.getHeight()+100 relative to the top of parent also??? I tested on my device, the clickable area does not move down as I want. I'm very confused here, any help is greatly appreciated.
The parameters to layout are relative to the parent view's upper left corner. X increases as you move to the right and Y increases as you move down. It is not relative to the view's current position.
You probably don't want to call layout on a child view outside of its parent's onLayout method. There are several other bits of internal bookkeeping that happen as a result of calling layout that will change internal state in a way you don't want for simple animations.
Typically layout is called like this:
child.layout(x, y, x + child.getMeasuredWidth(), y + child.getMeasuredHeight());
The parameters are absolute, with (0, 0) at the parent's upper left corner.
But if you're simply moving a view around for animation you probably want to do something more like:
// Adjust horizontally; dx = change in x position
child.offsetLeftAndRight(dx);
// Adjust vertically; dy = change in y position
child.offsetTopAndBottom(dy);
The parameters to the offset* methods are relative to the view's current position.
If you write a ViewGroup class that moves its child views around in this way, remember that you can get a layout request at any time. At that point your ViewGroup's onLayout method will try to position the child based on its usual layout rules and it will need to adjust this positioning to reflect any other accumulated movement you want to preserve.
I want to create a layout that contains an image on top of which I want to place many images and TextViews. I know how to place images on top of one another using RelativeLayout, but how to align them in a desired way? Eg I want an image to be exactly in a place where my “background” image has a specific black circle. Playing with values like android:layout_marginTop etc does not seem to do the effect in every screen.
So which is the proper way to handle these issues?
EDIT:
I cannot upload the images, but I uploaded a very simple sketch of what I want here:
http://imageshack.us/photo/my-images/715/buttonlayout.png/
all the buttons have also Icons and text (which must be a textview so that I can change it programmatically if need be)
You have to create a custom layout that places the image specifically where you want them relative to the size of the parent view. If you choose, you can override the LayoutParams and apply custom attributes to them for your custom view to read.
Anyway, to specifically place an item, say 30% down from the top and 20% from the left, you would overwrite onLayout().
#Override
public void onLayout(boolean c, int left, int top, int right, int bottom) {
super.onLayout(c, left, top, right, bottom);
int width = right - left;
int height = bottom - top;
View v = getTheChildView();
int viewL = left + (int)(width * .2f); // The left pixel is 20% down the total width of the parent view
int viewR = viewL + v.getWidth(); // The right pixel is the left pixel plus the measured width of the child view itself
int viewT = top + (int)(height * .3f); // The top pixel is 30% down the total height of the parent view
int viewB = top + v.getHeight(); // The bottom pixel is the top pixel plus the measured height of the child view itself
v.layout(viewL, viewT, viewR, viewB);
}
I have a layout where the Gallery height is WRAP_CONTENT (width is FILL_PARENT) with bottom margin of 80dp. This would leave 80dp at bottom of screen for something else.
The problem is how can I find out exactly how many pixels do I have in the height of this Gallery? I need this in order to set the size of the bitmap in Gallery's getView (as I want each image to take up a full Gallery screen) Various devices should give me different height pixels...
Apparently when I query Gallery.getHeight, it returns zero.
Also, if the image itself is smaller than the Gallery view port, I want to scale it up. However setScaleType(FIT_CENTER) seems to only scale down (if image is larger than viewport) yet does not scale up? Am I missing something?
Thanks in advance for your help.
Gallery is just another View, so any method defined for View will work. Use myGalery.getHeight();
From the View API reference page: http://developer.android.com/reference/android/view/View.html
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) method and queried by calling getPaddingLeft(), getPaddingTop(), getPaddingRight() and getPaddingBottom().
Update
Be careful when are you measuring it. If you use it on the constructor, the it will return zero since it was not drawn yet. Unless you are absolutely sure that the GridView will be visible by the time you measure it, you can measure by adding an View.OnLayoutChangeListener and implementing
public abstract void onLayoutChange (View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
http://developer.android.com/reference/android/view/View.OnLayoutChangeListener.html
or overriding protected void onSizeChanged (int w, int h, int oldw, int oldh)
u can get the total height & delete 80px from it ie(your Gallery height)
get total height by this code
Display display;
display = activity.getWindowManager().getDefaultDisplay();
display.getHeight()