I'm making a custom View thats derived from an ImageViewand I control where the image has to be within this ImageView using padding.
I have set OnClickListener on my custom ImageView that resizes it:
image.setOnClickListener(new ImageView.OnClickListener(){
#Override
public void onClick(View v) {
image.resize_image();
}
});
and this is how this function is looking like
public void resize_image(){
ViewGroup.LayoutParams params = getLayoutParams();
params.height = new_heigth;
params.width = new_width;
setLayoutParams(params);
}
After this resizing is done I don't want my displayed image to change size (only the custom ImageView is changing size so I can draw an extra stuff around this image) within my custom ImageView so inside onDraw(Canvas) member function I set the new padding
class custom_ImageView extends ImageView{
//...
#Override
protected void onDraw(Canvas canvas) {
//...
setPadding(new_left_padding, new_top_padding, new_right_padding, new_bottom_padding);
//...
}
//...
}
Result is that width and heigth are changed like I wanted but my displayed image is neither in the right position or size.
Interesting this is that if I add an extra line of invalidate(); in the end of my resize_image() and I click on my custom_ImageView twice - on the 2nd click image draws itself in right size and position like I wanted.
Can anyone tell me why this is happening?
I kind of worked around this by not using ImageView at all but just drawing image where it needs to be by using Canvas.drawBitmap(Bitmap, RectF, RectF, Paint)
This way I don't have to specify images location using setPadding within onDraw, but I can do it simply by specifying position using RectF.
Related
New Android programmer here.
I'm trying to display an .png image as a bitmap on Android. The only way I have been able to display the converted image at all is with a custom class that extends View. However, my image is too large to be displayed entirely on the screen and I would like to be able to scroll with it. But when I define a ScrollView and put the Canvas with the Bitmap into it, I get a blank screen. I had no luck setting this up with the layout file, so it is all done in the Activity class.
This is where the Activity is created:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ScrollView scroll = new ScrollView(this);
scroll.addView(new CustomView(this));
setContentView(scroll);
}
And this is my CustomView class:
private class CustomView extends View{
public CustomView(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas){
Bitmap bitmapMap = BitmapFactory.decodeResource(getResources(),R.drawable.resourceimage);
canvas.drawBitmap(bitmapMap,0,0,null);
this.setWillNotDraw(false);
}
}
And if I replace this line of code in my Activity: setContentView(scroll)
with this line: setContentView(new CustomView(this)), I can see the image, albeit not the entire image. So, is there a way to set this up in the layout files instead? Or is there something I'm missing that I need to declare in the ScrollView class?
EDIT: I would prefer not to use ImageView, because I would like to change the image in specific locations, and using bitmap seemed to be the easiest way to accomplish that, via x and y coordinates.
Your custom view needs to override the onMeasure method and properly set the measured width and height so that the parent views (in this case the ScrollView) can know how much space to allocate for the child.
I,m taking my first step into movement of bitmaps. From bits on the internet i,ve created this simple code. The bitmap moves across the screen from top left to top right it goes off the screen and back on at 0,0. What i want to do is add a button or method to manually move the image. I,m only using this single class and have noticed it does not use the main_activity xml Or does it?? If someone could show me on this 1 direction i can duplicate for the other directions. If youd like to add code so doesnt go off screen would be a bonus
public class MainActivity extends Activity {
int x=0;
int y=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new myView(this)); }
private class myView extends View{
public myView(Context context) {
super(context); }
#Override
protected void onDraw(Canvas canvas) {
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.richinch);
if (x < canvas.getWidth()){x +=10;}
else {x=0;}
canvas.drawBitmap(myBitmap, x, y, null);
invalidate();
}}}
Ive added this to the code and read a little on OnTouch listener. How would i add that to the region or Rectangle this would be very helpfull so effectively i,m using the Bitmap as a button if was button id know with onclick, Basicall im trying to make 2 Bitmap buttons to move the image Left Right for now.Eventually all directions. Please use names im using unless creating summit eg int etc
Paint green = new Paint();
green.setColor(Color.RED);
green.setStyle(Paint.Style.FILL);
////creating the shape////
Rect rect= new Rect();
rect.set(0, 0,x+50, x+50);
canvas.drawRect(rect,green);
Region region = new Region(0, 950, 100, 1030);
I am not exactly sure what you want to achieve, but if you would like to make an animation, avoid using onDraw() and just let ObjectAnimator do the "moving" for you. Here's a detailed tutorial on it.
The minimum code you need:
ObjectAnimator animation = ObjectAnimator.ofFloat(yourObject, "x", xDest);
animation.setDuration(500); // milliseconds
animation.start();
You are not using any xml
this part here:
setContentView(new myView(this)); is where you would add your xml file setContentView(R.layout.mainxml)
If you want to move around a bitmap with the touch of your finger check out these tutorials. They do exactly this and you will learn to use a SurfaceView
http://www.eis4u.com/2012/02/13/playing-with-graphics-in-android-part-i/
http://www.eis4u.com/2012/02/13/playing-with-graphics-in-android-part-ii/
http://www.eis4u.com/2012/02/13/playing-with-graphics-in-android-part-iii/
I've customized imageview but its just rotating its bitmap not the whole view. I don't want to use animation because I'm dragging imageview as well so moving animated imageivew results weird, so sticking to onDraw/draw, plus overriding draw is nothing doing special.
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
canvas.save();
canvas.rotate(rotationAngle, rotationW, rotationH);
super.onDraw(canvas);
canvas.restore();
}
how can I rotate the whole view not only its bitmap??
I did not get the provided answers intend here, but using
android:clipChildren="false"
for the parent ViewGroup
and overriding draw instead of onDraw did the job for me
For further information see:
Rotating imageview and its background without cropp
One must check width and height of the imageview, if Height > width then at the time of rotation width must be equal to height and same with height.
Make width and height equal to fill_parent and then rotate/translate/scale via matrix.
Starting with API 11, there is the following method available for each view:
.setRotation(float angle);
http://developer.android.com/reference/android/view/View.html#attr_android:rotation
Before API 11 you could add a rotate to the main-element of your view:
#Override
protected void onDraw(Canvas c) {
c.save();
c.rotate(...);
super.onDraw(c);
c.restore();
}
I have a FrameLayout that contains several ImageView. On the main activity, I record the touch events in order to move my FrameLayout and the images inside with the finger (drag).
For doing so, I am calling canvas.translate(x,y) inside the onDraw of the framelayout which is called by a invalidate() in the activity touch event handler.
Everything works like a charm except that after the translate, I am not able to click on my ImageView. In fact, the click listener of each image is still at the original place before the translate.
I have read that I should manually update the layout of each image after the translate but how to do that ? If I change the margin with the translate value, the images are going two times further ...
I would really appreciate any help on that one.
Cheers.
Here is the frameLayout where I translate the canvas in the onDraw() method (the ImageView are added to that FrameLayout in my main Activity).
public class TopView extends FrameLayout {
public float mPosX = 0;
public float mPosY = 0;
public TopView(Context context)
{
super(context);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(1920, 3200, Gravity.CENTER);
this.setLayoutParams(lp);
setWillNotDraw(false);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(this.mPosX, this.mPosY);
}
}
You can use setPadding(this.mPosX,this.mPosY,0,0) in the the constructor. It should work.
I am very new to Android and I am having problems figuring out how to layout views within a RelativeLayout programmatically. What I want to do is create 4 circles (child views) with a certain radius (say 50px) in the center of the RelativeLayout container, so it would look like I have an imaginary square in the center of the RelativeLayout and each vertex is the center for one of the circles.
I am able to draw the circle in the view; that is simple enough :)
class CircleView extends View {
...
protected void onDraw(Canvas canvas) {
// draw circle on canvas
}
}
What I cannot figure out is how to layout the views. It seems to draw them on top of each other, even though I am setting LayoutParams and an Id for each of the child views.
class Circles extends RelativeLayout {
public Circles(Context c) {
super(c);
addChildViews();
}
...
private void addChildViews() {
final Context c = getContext();
final CircleView v0 = new CircleView(c);
v0.setId(0);
final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF, 1);
params.addRule(RelativeLayout.ABOVE, 2);
v0.setLayoutParams(params);
addView(v0);
....
// and so on, with relative layout params for other 3 views
}
}
Can somebody put me on the right track please? I also don't know if I am not calling addChildViews at the right time in the drawing cycle, and if this is what is leading to them being drawn on top of each other. Many thanks for any help.
Two things
1)The default action of a View is to fill its parent, so by applying (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) as your LayoutParams, you're creating four views with heights and widths the size of your parent layout (presumably the screen), so you'd only see one as the others would be positioned offscreen.
To fix this, either set the size you want the circles to be as your LayoutParms,
float dpi = getResources().getDisplayMetrics().density;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int)(50.0f * dpi), (int)(50.0f * dpi));
or you could override the onMeasure(int x, int y) method in your Circle View like so
#Override
public void onMeasure(int x, int y) {
float dpi = getResources().getDisplayMetrics().density;
setMeasuredDimension((int)(50.0f * dpi), (int)(50.0f * dpi));
}
2) Don't set your View id to 0...I can't remember if it's system reserved or what, but it doesn't play nice.
Additionally, if you want all the circles centered in your Circles, you'll want to set its gravity to center like so.
public class Circles extends RelativeLayout {
public Circles (Context ctx) {
super(ctx);
this.setGravity(Gravity.CENTER);
addViewChildren();
}
This will center all of the Circles children, giving you the desired result.