I am attempting to experiment in creating my own Views by subclassing "View." I want to simulate a new Button type class that will be drawn with the onDraw where I simply draw a rectangle from the canvas being passed in. I then add that custom View into the layout XML file, but I cannot control its size. For example, I set the width to "fill_parent" and the height to "wrap_content" but I don't know what the content of my View is. (BTW, the LinearLayout that my view is in is oriented to "vertical")
Can anyone give me some pointers in how to control the size of my View? For example, how does my custom view know what parameters were set in the XML file?
Android cannot detect the contents of your Canvas, so it assumes the contents are 0x0.
To do what you're looking for, you have to override onLayout or onMeasure (onLayout is specified by Android developers as a way to lay out children instead). You will also need a way to calculate the size of your contents.
First, start with a member variable called Point mSize = new Point(0, 0);. In a method other than onDraw, but called just as often, you will want to replace this with the size of your contents. If you draw a circle that has a radius of 25, do: mSize.x = 50; mSize.y = 50;.
Next, I'll introduce you to this answer (for onMeasure). It shows how to set the size of an item based on its parent's dimensions (divided by 2, in this case). Then, you can pull the size from mSize.x and mSize.y and apply those dimensions.
Finally, calling invalidate() after you measure your new mSize should force the View to lay itself out again, and adjust to your new parameters. This is the one part I'm unsure of in this regard.
NB: Also, you could call setLayoutParams using a fixed width and height once you calculate the size of your Canvas contents. Not sure of the performance implications for this, though.
Related
I'm trying to place a small image on the top of a big one in a custom dialog.
I want the small one to be placed in a different place depending on a variable, which I called "pos". It contains a int value from 0 to 100, meaning percentage of the dialog width.
If pos = 0, I want to place the image in the left margin of the big one, if pos = 30 it should be placed in the 30% of the screen, starting from the left.
If pos = 50 I want it to able placed right in the middle, being 100 the maximum value for it and placing it in the right margin.
I include a draft to explain myself a bit better.
I tried with RelativeLayout.LayoutParams but I never get expected output.
Perhaps a simpler strategy is to extend ImageView, then create a custom image using Canvas commands in the onDraw method that draw the bitmap appropriately on the x axis with a background set to match your layout.
You can determine the width of the custom dialog in the the onMeasure method of your custom ImageView, so the returned bitmap (including empty background) can be the correct width, and the position of the smaller bitmap can be correctly apportioned.
Once you've created the class, which will take just a few minutes, you can add it to your XML layout with something like:
<com.domain.yourapp.YourCustomerImageView
android:id="#+id/bitmap_graph"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="3dp"/>
I Have some really strange problems.
First problem is as follow:
I read how to override onMeasure(). I did it. I was expecting that when I set width/height in onMeasure that they will be exactly the same in onDraw, but apparently this is not true.
Also I except that measuredWidth will be same as width in draw phase, but again it isn't true.
onMeasure could be called many times. On each call I invoke setMeasuredDimension with calculated width and height. So for example, first time my view should be 480 x 245, on second call I recalculate it again, based on parent of course, and it should be 90 x 245.
For my great surprise android somehow is just ignoring everything but the first call. So in this case my final view size is 480 x 245.
Second issue which is as follow:
My view height is match_parent, my parent height is 0. So how am I supposed to set right height on onMeasure when I don't know it ?
Any Idea how to make android not to ignore my setMeasureDimensions calls and how to set match_parent ?
The space that's allocated to your view doesn't depend only on the size you measured, here's a snapshot of the process :
View.onMeasure gets called during the measurement of your parent. You got your MeasureSpec that is essentially how much space at most you can take (very summarized).
Given these specs, you determine the size of yourself, logically measuring your own children and calling setMeasuredDimension
A while after, your parent assigns you concrete dimensions, based on what you measured (but this also means it can be different). Then as these will be your dimensions, that's the one you have to use. The callback called at this point is onLayout, and you shall layout your children in the process, based on the dimensions that were affected to you.
After all this, your View will be drawn, that is View.dispatchDraw being called and resulting for simple views to onDraw. Drawing yourself also means drawing your children if you're a ViewGroup.
When drawing, the system passes a Canvas whose dimensions are these of the screen, and using translation and clipping, the canvas is passed along views so that they draw themselves. This avoids allocation during draw. For this reason, if your want to know what space is dedicated to you, you should not use Canvas.getWidth or Canvas.getHeight which are the dimensions of the screen, but rather retrieve the clipped dimensions (Canvas.getClipBounds())
And finally, when you correctly retrieve the clip bounds, they should usually be the same as your width and height (View.getWidth or View.getHeight), but they might be different, for example if the canvas was scaled.
So to summarize :
onMeasure purpose, is to determine the size of children, so that ViewGroup can compute they're dezired size.
onLayout purpose is to affect a width and height to each view, propagating to children.
onDraw purpose is to render your view.
I have two views which overlap each other and one of them acts as a master to other. I am translating all the pinching and panning to scale and adjust the master view.
Now I wanna send this info over to the slave(Subclass of android.view.View). Being said that the other view doesn't respond to this dimensions. I have tried following methods
ViewGroup.LayoutParams params = this.getLayoutParams();
params.height = height;
params.width = width;
this.setLayoutParams(params);this.requestLayout();
setMeasuredDimension(width, height);
this.setMinimumHeight(height);
this.setMinimumWidth(width)
None of these seem to work.
Using the onTouchEvent I resize my TextureView and send the same to the other View object. On getting this Info about change in size which is in most cases greater than the parent dimensions(and screen size) the other view should also increase/change its size.
The subclassed view doesn't grow to the dimensions supplied to it. Moreover the increase is limited to the parent size(in my case its width: 1080 height: 1776) while it can go above that in the textureView which uses
textureView.setMinimumWidth(newWidth);
textureView.setMinimumHeight(newHeight);
Any ideas as to what maybe going wrong or a trusted way to change layout/dimensions across two views?
setLayoutParams => that would be the canonical way to position a View inside its parent.
setMeasuredDimension => this is used from View.onMeasure to tell the layout system what size your particular View wants. Use only if you're implementing your own View subclass.
setMinimumWidth/setMinimumHeight => tells the default View implementation what minimum size the View should have. If you implement View.onMeasure yourself, that shouldn't be needed.
All in all, if you stick with the standard Android framework components, setLayoutParams should be the place to look into.
The methods you've listed are all valid ways of setting sizes if used correctly, and in the right situations.
This is difficult to solve without further information.
In what way isn't it working? Is it causing a crash, or are the view sizes just not what you expect?
Where does that snippet sit in your code? I would guess its part of a custom class of your own which extends ViewGroup, but as you're new to stackoverflow we have no idea of your level of programming experience. It might be in completely the wrong place, and this refers to some other object entirely.
One thing I can suggest you check :
You mention your slave is a subclass of android.view.View, but this on its own is not enough to be able to use ViewGroup.LayoutParams. You need to ensure your slave is a direct or indirect subclass of android.view.ViewGroup.
Provide more of your code and info on what you are observing, and we will try and help you further.
Update:
Ok, so it's a TextureView that you are trying to resize.
I'd recommend you check the reported size of your TextureView after you set it's height and width. You could do this with break-points and run a debug, or you could use myTextureView.getWidth() and .getHeight(), and use Log statments to output them to the LogCat.
You can also check the size of the SurfaceTexture associated with your TextureView. Set a SurfaceTextureListener on your TextureView. When this listener is triggered, onSurfaceTextureAvailable() will provide the width and height of the SurfaceTexture.
I suggest this because you may find that you are able to change the size of the TextureView, but it is the content of the the TextureView that is not changing size. In this case you can override TextureView.onSizeChanged(int w, int h, int oldw, int oldh) to define the necessary transform to scale your content between the old and new sizes.
How it is possible to stretch the image manually to our required pixel position.in my android application i want to stretch my image to the specified position by dragging the end points of it.can anybody suggest me how to do this............
You can use an imageview with the attribute
android:scaleType="fitXY"
This will make the image to fit the bounds of the imageview.
To modify the image on click or touch, you will need add a ontouchlistener to the view. And on the based on the view getTop and and getLeft, you will need to set the layout params of the view to increase or decrease the size.
Or you will need to extend a view and override the onDraw method, in that method you can use the canvas.drawBitmap method to specify the size of the bitmap.
Either way you will need to use the onTouchListener.
I am drawing a custom view in my application which basically takes arguments(XML) as the text to display and then keeps on rotating it infinitely.
While I was making this control I had a few doubts which I want to ask:
I have made 2 of my stylable attributes which I have declared in the attrs.xml file. These attributes are to set the width and the width of the circle used in my control. These values I would use in the ondraw method and the onmeasure method. I ran my program by declaring just these but there was an error which asked me to put android:width and android:height attributes. My question is why would I need those if I am already using my custom attributes to define the height and the width of my view
I am coding on a mac. Now when I was making my attrs.xml file, to get the autocomplete list which we usually get by ctrl+space was not showing up. Why is that. For e.g., i wanted to know what values can I give the format attribute of my custom attribute that like I am demostrating in the following:
<attr name ="somename" format="value I wanted to find out through autocomplete"> . Why is the autocomplete not popping up? It does pop up when I am making a.java file.
In my ondraw() method I wanted to draw a circle. Now for this I would require the co-ordinates of the center of the circle. So what I do is put 0, 0. But this is not correct. I want the circle to be at the center of the parent view it is in. So if my view is in a hierarchy I want it to respect that. I want to give the co-ordinates relative to the parent view. What is happeining right now is that it is being drawn at the top left corner of my screen. This is what I don't want. What do I do to achieve this?
why would I need those if I am already using my custom attributes to define the height and the width of my view?
This is because Android needs to know how and where to put your view in the layout. You can implement your view to make use of your custom height/width requirements by overriding View.onMeasure() to return your own size parameters. You can then just set android:layout_width="wrap_content" android:layout_height="wrap_content" in your layout file.
Why is the autocomplete not popping up? It does pop up when I am making a.java file.
Autocomplete and autodoc implementation for Android xml files is shaky at best, so it's not really surprising that it doesn't work. I'm not aware of a fix and AFAIK it's an IDE bug.
In my ondraw() method I wanted to draw
a circle. Now for this I would require
the co-ordinates of the center of the
circle. So what I do is put 0, 0. But
this is not correct. I want the circle
to be at the center of the parent view
it is in. So if my view is in a
hierarchy I want it to respect that. I
want to give the co-ordinates relative
to the parent view. What is happeining
right now is that it is being drawn at
the top left corner of my screen. This
is what I don't want. What do I do to
achieve this?
If you implemented onMeasure() correctly, the coordinates relative to parent should be taken care of already. To get the center of your view use the following code:
void onDraw(Canvas canvas)
{
int centerX = this.getWidth() / 2;
int centerY = this.getHeight()) / 2;
//..draw code here
}
Edit
Here's an example with source code that should help: http://mindtherobot.com/blog/272/android-custom-ui-making-a-vintage-thermometer/