I have created a custom view class to use in a project I'm working on. To put is simply, I'm displaying an image, then adding images on top of the original image (currently by clicking on the image, but that's not final).
I have these 2 methods in my custom view:
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
for (Drawable d : drawableList)
{
d.draw(canvas);
}
}
public void AddPoint(float x, float y)
{
Drawable tempDrawable = pin;
tempDrawable.setBounds((int)x, (int)y, (int)x + 50, (int)y + 50);
drawableList.add(tempDrawable);
invalidate();
}
The AddPoint() method is called in an OnTouchListener and is passes the coordinates of the touch event.
The way it currently works is it displays the main image, but will only display the most recent images where I clicked, previous ones just disappear.
Does anybody know what I am doing wrong here?
I've figured out what I was doing wrong.
The line of code:
Drawable tempDrawable = pin;
I changed to:
Drawable tempDrawable = mainRes.getDrawable(R.drawable.pin);
I got mainRes from the init(Context context) method I wrote in the custom View class.
Related
I want to divide the image into sub images and when I click on a part of the image will give me the name of the region, for example, this is my question how to recognize a region from the image, or how to divide the image into sub-images and use it in imageViews
And thank you in advance
In my opinion #fractalwrench's idea is quite good for your case. Basic steps are listed below.
Subclass Android ImageView. For example, MultiRegionImageView.
Override its onTouchEvent method. (This method gets called whenever user touches the view)
User touches the image and thereby onTouchEvent is called and provides the exact touch point (x, y).
Declare another method or interface which determines at which region a given point is. For example, getRegionByPoint(int x, int y)
If you would like to highlight that region boundaries, you could use paths. First off, you should define paths and save them into a raw file (XML, for example), then using region ID, fetch its path and finally draw that path over the main image.
For drawing a path over the main image, you should also override onDraw method of ImageView class and use canvas.drawPath();
public class MultiRegionImageView extends ImageView {
RegionProvider mRegionProvider;
int mId = -1;
private Paint mPaint;
public MultiRegionImageView(Context context) {
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mId = mRegionProvider.getRegionIdByPoint(event.getX(), event.getY());
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mId != -1) {
canvas.drawPath(mRegionProvider.getRegionBoundaryPath(mId), mPaint);
}
}
public interface RegionProvider{
int getRegionIdByPoint(float x, float y);
Path getRegionBoundaryPath(int id);
}
}
You should only need one ImageView to display the map. If you override onTouchEvent(MotionEvent e), you can get the position which is being touched in the View. If you store the position and shape of each region in some sort of List, you can check whether a touch event is within a region (and display whatever text you need to).
currently I am trying to make an animation where some fish move around. I have successfully add one fish and made it animate using canvas and Bitmap. But currently I am trying to add a background that I made in Photoshop and whenever I add it in as a bitmap and draw it to the canvas no background shows up and the fish starts to lag across the screen. I was wondering if I needed to make a new View class and draw on a different canvas or if I could use the same one? Thank you for the help!
Here is the code in case you guys are interested:
public class Fish extends View {
Bitmap bitmap;
float x, y;
public Fish(Context context) {
super(context);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.fish1);
x = 0;
y = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, x, y, null);
if (x < canvas.getWidth())
{
x += 7;
}else{
x = 0;
}
invalidate();
}
}
You can draw as many bitmaps as you like. Each will overlay the prior. Thus, draw your background first, then draw your other images. Be sure that in your main images, you use transparent pixels where you want the background to show through.
In your code, don't call Invalidate() - that's what causes Android to call onDraw() and should only be called from somewhere else when some data has changed and needs to be redrawn.
You can do something like this, where theView is the view containing your animation:
In your activity, put this code in onCreate()
myAnimation();
Then
private void myAnimation()
{
int millis = 50; // milliseconds between displaying frames
theView.postDelayed (new Runnable ()
{
#Override public void run()
{
theView.invalidate();
myAnimation(); // you can add a conditional here to stop the animation
}
}, millis);
}
I have an ActionBar icon (the main one on the left, not an action item) that I would like to animate.
I am setting my ActionBar's icon in my Activity like this:
getSupportActionBar().setIcon(icon)
where icon is a Drawable produced by a library that converts a custom XML view into a bitmap. This XML view is a RelativeLayout with a background image and a TextView on top.
Today, when I have to update the TextView I simply re-generate the icon and call setIcon again. Instead, I would like to get a hold of my TextView and apply some animation effect on it, like fade-out and then fade-in after updating it (maybe never having to call setIcon, just re-use the same one).
Not sure how to go about this. Can someone recommend an approach?
EDIT: trying this approach:
In MyActivity:
Drawable myDrawable = new MyDrawable();
supportActionBar.setIcon(myDrawable);
and:
public class MyDrawable extends Drawable {
private Paint paint;
private RectF rect;
public MyDrawable() {
this.paint = new Paint();
this.rect = new RectF();
}
#Override
public void draw(Canvas canvas) {
paint.setARGB(255, 0, 255, 0);
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
rect.right = 20f;
rect.bottom = 20f;
canvas.drawRoundRect(rect, 0.5f, 0.5f, paint);
}
#Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
#Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
}
Nothing shows up. I verified that onDraw gets called. Something suspicious to me is that canvas has both height & width set to 1.
A proper approach for it would be to forget the XML layout and create a custom Drawable.
An instance of this custom drawable will be set to the icon on the ActionBar and call invalidateSelf() whenever necessary to redraw (due to animation, for example).
The drawable can hold reference to other drawables (e.g. BitmapDrawable to have something from the /res/ folder or a Color or Gradient drawable for a background shade) and call (for example) bgDraw.draw(canvas) during the onDraw callback.
It can also draw stuff directly on the canvas that is given to it during onDraw callback. With the canvas you can draw circle, lines, areas, path and text directly on it.
edit:
very simple animation example (didn't check the code, likely typos):
private long animationTime;
public void doAnimation(){
animationTime = System.currentTimeMilis() + 3000; // 3 seconds
invalidateSelf();
}
public void onDraw(Canvas canvas){
// do your drawing.
// You can use difference between
// currentTimeMilis and animationTime for status/position
...
// at the end
if(animationTime > System.currentTimeMilis())
invalidateSelf();
}
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 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.