I use Android studio and I have this image with a transparent background. Whenever i click on it it'll bring me to another Activity. But even when I click on the transparent part of the image it'll bring me to the other Activity.
Is it possible to make the nontransparent part clickable (or touchable) and the transparent part unclickable?
Yes this is possible but it becomes much more difficult than just adding an OnClickListener.
The trick is to use a Touch listener instead of click and on either a DOWN or UP event take the position and then either use some simple maths to work out whether it was a transparent area (if the design is a simple one) or, do some more complicated stuff to work out your pixel values at the centre.
new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
If (event.getAction() == MotionEvent.ACTION_DOWN) {
final int x = (int) event.getX();
final int y = (int) event.getY();
//now map the coords we got to the
//bitmap (because of scaling)
ImageView imageView = ((ImageView)v);
Bitmap bitmap =((BitmapDrawable)imageView.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(x,y);
//now check alpha for transparency
int alpha = Color.alpha(pixel);
If (alpha != 0) {
//do whatever you would have done for your click event here
}
}
return true; //we've handled the event
}
}
Related
I'm working on my first game app, when user touches an image the app shows a message to the user (or does other things in other situations).
My photos are non-geometric shapes (for example animal photos) with 100% transparent backgrounds
(I used Photoshop and saved them in PNG format.)
My problem is that I need it to react (and show the message,...) only when the animal shape itself (NOT the imageview's transparent background/corners) is touched by user.
I used the solution that's offered in this question to find out if the pixel that's touched is transparent or not, but it doesn't work the way I need. Here's part of my onCreate() method in MainActivity.java:
tempIV=(ImageView)findViewById(R.id.birdIV);
final Bitmap bitmap = (BitmapDrawable)tempIV.getDrawable()).getBitmap();
tempIV.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
int x = (int)event.getX();
int y = (int)event.getY();
int transparency = bitmap.getPixel(x,y);
if (transparency == 0)
{ //Do nothing
return false;}
else {
Toast.makeText(MainActivity.this,
"This is an animal!", Toast.LENGTH_LONG).show();
}
return true;
}
});
What should I do?
Try using this :-
if (bitmap.getPixel(x, y) == Color.TRANSPARENT)
{
return false; //don't react
}
else
{
return true; //do something like intent
}
I have used 4 different colored custom shape buttons. I am trying to implement an ontouch listener by getting the pixel color as shown below
#Override
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
return isPixelTransparent(v, x, y) || v.onTouchEvent(event);
}
private boolean isPixelTransparent(View v, int x, int y) {
Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
int color = Color.TRANSPARENT;
try {
color = bmp.getPixel(x, y);
} catch (IllegalArgumentException e) {
// x or y exceed the bitmap's bounds.
// Reverts the View's internal state from a previously set "pressed" state.
v.setPressed(false);
}
return color == Color.TRANSPARENT;
}
However the rectangular area of the buttons overlap so the buttons underneath dont get pressed if pixel is transparent. Also please note all the buttons have large white text. I have done lots of searching but cannot figure out how to go about it, any help would be much appreciated please.
XML
<za.co.####.####.DiamondShapeButton
android:id="#+id/button_resources"
style="#style/NavigationButton"
android:layout_width="150dp"
android:layout_height="150dp"
android:text="#string/resources"
custom:diamondColor="#color/red"/>
<za.co.####.####.DiamondShapeButton
android:id="#+id/button_practise"
style="#style/NavigationButton"
android:layout_width="150dp"
android:layout_height="150dp"
android:text="#string/practise"
custom:diamondColor="#color/blue"/>
<za.co.####.####.DiamondShapeButton
android:id="#+id/button_tests_exams"
style="#style/NavigationButton"
android:layout_width="150dp"
android:layout_height="150dp"
android:text="#string/my_tests_exams"
custom:diamondColor="#color/orange_light"/>
<za.co.####.####.DiamondShapeButton
android:id="#+id/button_track_studies"
style="#style/NavigationButton"
android:layout_width="150dp"
android:layout_height="150dp"
android:text="#string/track_studies"
custom:diamondColor="#color/black"/>
</za.co.####.####.DiamondShapeLayout>
A View only knows about its own rectangular space, not that of the views that might be behind it. So if a View has a transparent pixel, it will only know that its own pixel is transparent, not anything about the views that may be behind it.
If you want to have a view bypass some event handling, it will need to know about the views behind it and if they wish to handle the event instead. You can't do this with pixel color of a single view - you will have to code this logic yourself based on the overall layout of the views.
I am currently developing an Android app that displays multiple images (as ImageView's) stacked on top of each other. Here is how the layers are currently configured:
Background layer: scales the entire screen, must be clickable
Foreground layer: scales the entire screen, must be clickable,
contains transparency which allows the user to see some of the
background layer
The problem I face is with the foreground layer. I am assigning the onClick() method to the imageview, but the method is being called whether they hit the portion of the image which is visible as well as the part which contains transparency. I only want the foreground ImageView onClick() method to be called when the user clicks a portion of that imageview that is not transparent.
This is what the scenario looks like:
The diagonal lines represent the transparent portion of the Foreground image. If a user touches this space, I want it to access the Background image instead of the Foreground image. Thank you for any assistance you can provide.
Here is the solution I implemented (Thanks to answer below):
//ontouchlistener - gets X and Y from event
private void setClick(View view)
{
view.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View v, MotionEvent event)
{
int imageId = getImageId((int)event.getX(), (int)event.getY());
if (imageId >= 0)
performActions(imageId);
return false;
}
});
}
//get the ID of the first imageview (starting from foreground,
//working backwards) which contains a non-transparent pixel
private int getImageId(int x, int y)
{
ViewGroup parent = (ViewGroup) findViewById(R.id.relative_layout);
for (int a = parent.getChildCount()-1; a >= 0; a--)
{
if (parent.getChildAt(a) instanceof ImageView)
if (!checkPixelTransparent((ImageView)parent.getChildAt(a), x, y))
return parent.getChildAt(a).getId();
}
return -1;
}
//get bitmap from imageview, get pixel from x, y coord
//check if pixel is transparent
private boolean checkPixelTransparent(ImageView iv, int x, int y)
{
Bitmap bitmap = ((BitmapDrawable) iv.getDrawable()).getBitmap();
if (Color.alpha(bitmap.getPixel(x, y)) == 0)
return true;
else
return false;
}
This one sample makes ImageView's transparent area not clickable.
ImageView:
ImageView imgView= (ImageView) findViewById(R.id.color_blue);
imgView.setDrawingCacheEnabled(true);
imgView.setOnTouchListener(changeColorListener);
OnTouchListener:
private final OnTouchListener changeColorListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
int color = bmp.getPixel((int) event.getX(), (int) event.getY());
if (color == Color.TRANSPARENT)
return false;
else {
//code to execute
return true;
}
}
};
If your foreground image is not just a rect but a complex image and you really need that the touch is pixel-precise, you may use
http://developer.android.com/reference/android/view/View.OnTouchListener.html
foregroundImage.setOnTouchListener(new View.OnTouchListener(){...});
The MotionEvent in the callback will contain what kind of action happened (e.g. Touch up) and the exact location.
If you know the exact size of the foreground image as it is displayed, you can figure out which pixel of it was clicked, then check if that pixel's alpha is 0. Or you may need to apply some scaling if the image was scaled. This may get quite tricky since depending on the screen size and proportions the image may have been scaled/positioned differently. This also depends on the layouts your were using.
For the check of the pixel value you'd probably need to keep in memory the Bitmap object containing your foreground's image data as well.
Frankly, I doubt you'd really need all that precision unless your foreground image is really of a very irregular shape.
Bitmap.createBitmap(v.getDrawingCache() and imageView.setDrawingCacheEnabled(true) are depreciated so you can do this by the following snippet code:
imageView.setOnTouchListener { v, event ->
val bmp = convertViewToDrawable(v)
val color: Int = bmp.getPixel(event.x.toInt(), event.y.toInt())
if (color == Color.TRANSPARENT)
return#setOnTouchListener false
else {
Toast.makeText(baseContext, "image clicked", Toast.LENGTH_SHORT).show()
return#setOnTouchListener true
}
}
private fun convertViewToDrawable(view: View): Bitmap {
val b = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight,
Bitmap.Config.ARGB_8888)
val c = Canvas(b)
c.translate((-view.scrollX).toFloat(), (-view.scrollY).toFloat())
view.draw(c)
return b
}
I have a large image on the screen and I want to display a small image on that image where I touch the screen. but I do not know how to change the position of the image when I touch on the screen and the small image must display where ever I touch on screen.
any suggestions or hint will be appreciative.
thanks
Suppose you have your moving bitmap already in an ImageView which is part of your RelativeLayout.
Whenever the user touches the screen, you just have to change the position of the ImageView, by changing its margins.
You should try something like this:
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN)
{
RelativeLayout.LayoutParams params = myImageView.getLayoutParams();
params.setMargins(event.getX(),event.getY(), 0, 0);
myImageView.setLayoutParams(params);
}
}
User first the method onTouchEvent() to get the position of your touch.
Then i suppose you have your Bitmap placed in a UIElement like for example ImageView? And if you're using AbsoluteLayout you can set the ImageView object at the same coordinates you reveiced in the ontouchEvent.
#Override
public boolean onTouchEvent(MotionEvent event) {
event.getX();
event.getY();
}
I am making a canvas and setting its background which is an image
I am adding text on it by canvas. Drawtext method which works perfectly alright
now I want these text to be clickable but i couldn't find any method
The other method I could think of was to add text box on canvas add write on click event of these text box but could not find any example related to this can anybody suggest what to do.
Canvas is a space where you can just draw some graphics, thus the only way to do what you want is detecting when the user click the surface the canvas is drawn on (e.g. a SurfaceView), and using the coordenates you just fire an event. Of course, you need to verify whether the click was done on the specific part you want (e.g. the area where you drew a button or something).
Use the onTouchEvent method. Here is an example I used for finding out if the user's click coordinates are in a List of rectangles (aka buttons):
#Override
public boolean onTouchEvent( MotionEvent event) {
super.onTouchEvent(event);
int x = (int)event.getX();
int y = (int)event.getY();
xStored = x; yStored=y;
if (event.getAction()==MotionEvent.ACTION_UP){
}else if(event.getAction()==MotionEvent.ACTION_DOWN){
System.out.println("Touching down!");
for(Rect rect : rectangles){
if(rect.contains(x,y)){
System.out.println("Touched Rectangle, start activity."+x+","+y);
invalidate();
}else{
}
}
}else if(event.getAction()==MotionEvent.ACTION_MOVE){
}
this.postInvalidate();
return true;
}