Android divide an image in multiple region for onClick events - java

In this application, I have for example an image representing the map of Germany. I want to be able to click on one specific state, for example, Bavaria and something should happen (on click function).
I can maybe place a table layout on top of the image filled whit blank images and activate the on click method only on the one covering the states, but this is probably bad coding, and I think will be poorly compatible whit other types of device, tablet or bigger/smaller screen.
Another solution can be to create two image of the map. One with different colors of the states, and another with the desired layout to show. Put the colored one as invisible on top of the second one.
XML :
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/background" >
<ImageView
android:id="#+id/image_areas"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:visibility="invisible"
android:src="#drawable/mapcolor" />
<ImageView
android:id="#+id/image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:src="#drawable/mapdisplay"/>
</FrameLayout>
Java :
public boolean onTouch (View v, MotionEvent ev) {
final int action = ev.getAction();
// (1)
final int evX = (int) ev.getX();
final int evY = (int) ev.getY();
switch (action) {
case MotionEvent.ACTION_DOWN :
if (currentResource == R.drawable.mapdisplay) {
}
break;
case MotionEvent.ACTION_UP :
// Switch to a different image, depending on what color was touched.
int touchColor = getHotspotColor (R.id.image_areas, evX, evY);
// Switch to a different image, depending on what color was touched.
ColorTool ct = new ColorTool ();
int tolerance = 25;
nextImage = R.drawable.mapdisplay;
// (3)
if (ct.closeMatch (Color.RED, touchColor, tolerance)) {
// Do the action associated with the RED region
// onClick function here ?
} else {
//...
}
break;
} // end switch
return true;
}
Color Tool :
public class ColorTool {
public boolean closeMatch (int color1, int color2, int tolerance) {
if ((int) Math.abs (Color.red (color1) - Color.red (color2)) > tolerance ) return false;
if ((int) Math.abs (Color.green (color1) - Color.green (color2)) > tolerance ) return false;
if ((int) Math.abs (Color.blue (color1) - Color.blue (color2)) > tolerance ) return false;
return true;
} // end match
} // end class
As expected this is not working for me. Can someone explain to me this method or a good way to have an image "map" with multiple regions to click?

I was thinking of having a 2D matrix having a map of the states. There should be an initial version of the matrix which maps with different numbers for the different region based on their locations. For larger or smaller screen size, the matrix needs to be dynamic and remapped among the pixels. Let us consider the following grid as an example.
--------------
00111122224444
01111222222444
11122222444444
11222244444433
12222444444333
22224444444433
22255444444333
22555554443333
25555555433333
--------------
We can see 5 states here with their respective numbering in the matrix which follows the map. If the screen size doubles, you need to translate the values to have a larger segment and vice versa.
I was thinking of plotting such matrix which can be translated into larger or smaller dimensions based on the screen size. Now you need to set the image of the map as screen background and take an onTouchListener to get the pixel of the area touched to determine which area is being clicked.
This is just to give an idea of how this problem could be solved. I found one similar idea here in the MapChart. Hope that helps!

Related

Determine if a TextView requires scrolling

Inside CursorAdapter's bindView() I bind data to the following layout:
A TextView and two Buttons : "UP" and "DOWN".
The TextView is defined in XML like so:
<TextView
android:id="#+id/tv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="25dp"
android:paddingRight="25dp"
android:paddingTop="25dp"
android:scrollbars="vertical"
android:textAlignment="textStart"
android:textColor="#5c6284"
app:autoSizeMaxTextSize="40sp"
app:autoSizeMinTextSize="20sp"
app:autoSizeTextType="uniform" />
A vertical scrolling behavior is applied to the TextView, which is being controlled by the "UP and "DOWN" Buttons.
I would like to determine if the TextView requires scrolling ( is long enough to not fit its provided drawing area ) so that I can enable/disable the "UP" and "DOWN" buttons accordingly.
I'm currently reading BaseMovementMethod's scrollDown function, thinking of applying its measuring logic to my adapter, though I have the feeling that it should be much simpler. Maybe a built in behavior that I'm not aware of.
Is there a better way to achieve this, other than my suggested approach?
What I would do is put the textview inside a scrollview like so:
<ScrollView
android:id="#+id/scroller"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<TextView
android:id="#+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test texts here"/>
</ScrollView>
In your activity, execute these lines:
boolean needScrolling = false;
if(scroller.getHeight() < tv_content.getHeight()) needScrolling = true;
You can use Static Layout class. If you set it up with your TextView's parameters you'll be able to calculate the height of the rendered text.
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;
StaticLayout myStaticLayout = new StaticLayout(text, myTextView.getPaint(), myTextView.getWidth(), alignment, spacingMultiplier, spacingAddition, includePadding);
float height = myStaticLayout.getHeight();
Then you can compare the height of your text and height of your TextView and figure out if it will require scrolling or not.
You can also try to manually create a Paint object with your min text size if myTextView.getPaint() approach does not work.
Calculate mTextView's height without data and with data and then compare it
mTextView.post(new Runnable() {
#Override
public void run() {
int lineHeight=mTextView.getCompoundPaddingBottom()+ mTextView.getCompoundPaddingTop()+mTextView.getLineHeight();
int height=mTextView.getHeight()-(mTextView.getCompoundPaddingTop()+mTextView.getLineHeight());
if (height>lineHeight){
}
}
});

How to get correct ImageviewId after rotation of layout

I have a layout with 2*2/3*3/4*4... ImageView. and some of them randomly colored like this:
For ranodomly colored one of Imageview, I have Use this code:
Random random = new Random();
id = array_image1.get(random.nextInt(array_image1.size()));
ObjectAnimator animator = ObjectAnimator.ofInt(findViewById(id), "backgroundResource", R.drawable.original_img, R.drawable.org_state).setDuration(1500);
animator.setStartDelay(1500);
animator.setEvaluator(new ArgbEvaluator());
animator.start();
And I'm handling some click event on colored ImageView like this:
for (int i = 0; i < array_image11.size(); ++i) {
final int btn = array_image11.get(i);
findViewById(btn).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if ((findViewById(id)).equals(findViewById(btn)))
//Inform the user the button has been clicked
{
//forward
findViewById(id).setBackgroundResource(R.drawable.original_img);
}else {
//backward
Toast.makeText(StaticSpatial.this, "wrong", Toast.LENGTH_SHORT).show();
}
});
}
There is no problem till above.
But When I'm adding a random rotate animation code like this:
int n;
int[] a=new int[]{1,2};
final Random rnd = new Random();
n=a[rnd.nextInt(a.length)];
if(n==1)
{
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(l4, View.ROTATION, 0, 90);
rotateAnimator.setDuration(2000); // miliseconds
rotateAnimator.start();n);
}
else
{
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(l4, View.ROTATION, 0, 90);
rotateAnimator.setDuration(2000); // miliseconds
rotateAnimator.start();
}
After rotation image look like this(i.e. colored Imageview chage it's position):
After adding this rotate animation code my clickEvent not get correct ImageView id.
i.e. when imageview change it's position,their id should be go with that positon. but imageview id ramains at same postion.
So How to get required ImageviewId after rotation
Update:
After using azizbekian's answer(now using animator instead of animation) I found correct image-view id , but only first time.
i.e. first time when Activity starts it works good but when I'm going to a new view(say 3*3) and return back again to this view(2*2),it returns wrong image-view id till Activity restarts again.see my updated code for ref.
Explanation of working and issue:
I have already said that there are many matix of Imageview such as 2*2/3*3/4*4..... So when we start Application first load 2*2 matrix of imageview and when we click the odd colored imageview it goes to 3*3 matrix but when we click other than odd colored imageviewthen it goes to next level say 3*3.So when app start first time when I click on odd colored imageview it goes to 3*3 matrix but when return again on 2*2 after clicking other than odd colored imageview.and then again when we click on colored imageview it not get correct image id. and if any other query plz ask?
How to resolve this issue ?
When ImageView changes it's position, their id should go with that position. But ImageView id remains at same position.
That's because you are using Animation, which in fact doesn't change your View's position. What is does it makes an illusion of animation, so it only changes that view's matrix, but doesn't perform layout changes to the view.
Use Animator API instead of Animation.
Update
Given this animation xml:
<set xmlns:android="schemas.android.com/apk/res/android">
<rotate
android:fromDegrees="0"
android:toDegrees="90"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000" />
</set>
This can be substituted with following:
ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(yourView, View.ROTATION, 0, 90);
rotateAnimator.setDuration(2000);
rotateAnimator.start();
Update:
Just set rotation zero at every load of view (or layout) like this:
mylayoutname.setRotation(0);
Because after rotation it doesn't go to zero degree automatically until activity stops.
Maybe instead of using rotation you can store the Ids of the ImageViews in a List or Array and the Id of the currently colored ImageView in a separated variable, and when you have to rotate instead you can simply select one random ImageView from the List/Array (excluding the currently colored one), remove the color from the previous one and color the new one.
By the way, when you have 3x3, 5x5, 7x7 etc. layouts is the middle ImageView never colored? 'Cause in those cases a rotation wouldn't change anything (visually, at least). I mean, a rotation works for choosing a random square in a layout of 2x2 squares, but not in any other case. Do you need to choose the squares randomly or do they need to always be chosen by a rotation? (I hope what I mean is clear...)

ImageView within an AbsoluteLayout, How to set x, y coordinates of the ImageView?

What I'm trying to do is create a poorman's version of a gps map. I've setup a "map" picture as the background of an AbsoluteLayout, and then created a tiny 20x20 square picture that I need to move to different coordinates. How do I go about doing this in the Java code?
<AbsoluteLayout
android:id="#+id/llMapContainer"
android:layout_width="match_parent"
android:layout_height="390dp"
android:layout_x="0dp"
android:layout_y="44dp"
android:background="#drawable/a4000vert"
android:orientation="vertical" >
<ImageView
android:id="#+id/imgLocation"
android:layout_width="20px"
android:layout_height="20px"
android:layout_x="312px"
android:layout_y="300px"
android:src="#drawable/location" />
</AbsoluteLayout>
I have this setup in my Java file:
iv = (ImageView) findViewById(R.id.imgLocation);
but now I can't seem to find any methods that would allow me to set the x and y coordinates.
AbsoluteLayout is depreciated and its use is strongly discouraged. You should switch to using some other form of ViewGroup, such as RelativeLayout.
Once you're using RelativeLayout, you can use the RelativeLayout.LayoutParams class to specify the child's size and position (as well as various other parameters) when adding it to the parent RelativeLayout.
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(100,200); // The desired size of the child
params.setMargins(50,50); // Position at 50,50
mRelativeLayout.addView( mViewToAdd, params);
Here's how you can set x and y coordinates of your ImageView inside the AbsoluteLayout:
private void setLocation(int x, int y) {
final ImageView iv = (ImageView) findViewById(R.id.imgLocation);
final AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) iv.getLayoutParams();
lp.x = x;
lp.y = y;
iv.setLayoutParams(lp);
}
I agree with Trevor though that you might want to avoid using AbsoluteLayout if possible since it has been deprecated.

How to draw a line in an IF statement for java

I am trying to program an androd application where if there is input on two places of the screen in sucsession then it will draw a line between the two points. I have already set up "X" and "Y" values that work and columns and rows are defined by the "X" and "Y" values. After those i have an IF statement that needs to draw a line between the two points. Say if column one and row two are selected and then colum one and row three are selcted I want a line to be drawn between the two points. Also I am not totally sure how to use the MotionEvent stuff or how to put the touch actions into the IF statement.
final View touchView = findViewById(R.id.touchView);
touchView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
String.valueOf(event.getX() + String.valueOf(event.getY()));
double c = event.getX();
double column = Math.floor(event.getX()/(480/12));
double r = event.getY();
double row = Math.floor(event.getY()/(630/12));
if (column == 0 && row == 2 //there should be more stuff here
) {
//I dont know how to draw a line in here, please help
}
return true;
}
});
}
Rather than explain the details here, I'll point you to these pieces of sample code from the ApiDemos sample project that comes with the SDK, that probably do exactly what you want:
DrawPoints.java
TouchPaint.java
The basic idea is to store X and Y coordinates in your touch event handler, invalidate the View, and then draw the lines in the onDraw method using Canvas operations such as drawLine.
You do neew to have a tool to draw the line, most suitable for you it seems to be Canvas. If you don't know anything about Canvas together with Android yet i suggest you to look into some examles that Android leaves us. Ones you have done that, this is going to be a simple task.

Android - combine multiple images into one ImageView

I'm looking for help developing (or a library) which can allow me to merge together multiple images into one imageview.
My application is grouping together interactions between users, instead of displaying them singularly, and therefore I would like to merge all of their avatars, so that one adapter cell visualizes a "group".
A fantastic example of this is done on facebook.com's chat as such:
My question is, how can I provide this functionality in Android / Java? Presumably, it could a number of images between 1 and 4. Please let me know of any advice you can give :)
You can use MultiImageView.
Add dependency in app.gradle:
compile 'com.github.stfalcon:multiimageview:0.1'
Add MultiImageView to layout xml file
<com.stfalcon.multiimageview.MultiImageView
android:id="#+id/iv"
android:layout_width="100dp"
android:layout_height="100dp"/>
In java class find view by id:
final MultiImageView multiImageView = (MultiImageView) findViewById(R.id.iv);
For adding image to MultiImageView use method addImage(Bitmap bitmap). For exapple:
multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar1));
For setting shape of MultiImageView use method setShape(MultiImageView.Shape shape).
multiImageView.setShape(MultiImageView.Shape.RECTANGLE);//Rectangle with round corners
multiImageView.setShape(MultiImageView.Shape.CIRCLE);//Circle
multiImageView.setShape(MultiImageView.Shape.NONE);//Without shape
Check github link for more information:
I think it is what you needed
You should overlap bitmaps onto another bitmap. A first approach are this:
Merge bitmaps
You can play with matrix and orders and sizes for a complex UI.
i know it's an old question but maybe it will help somebody else.
private Bitmap mergeThemAll(List<Bitmap> orderImagesList) {
Bitmap result = null;
if (orderImagesList != null && orderImagesList.size() > 0) {
// if two images > increase the width only
if (orderImagesList.size() == 2)
result = Bitmap.createBitmap(orderImagesList.get(0).getWidth() * 2, orderImagesList.get(0).getHeight(), Bitmap.Config.ARGB_8888);
// increase the width and height
else if (orderImagesList.size() > 2)
result = Bitmap.createBitmap(orderImagesList.get(0).getWidth() * 2, orderImagesList.get(0).getHeight() * 2, Bitmap.Config.ARGB_8888);
else // don't increase anything
result = Bitmap.createBitmap(orderImagesList.get(0).getWidth(), orderImagesList.get(0).getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
for (int i = 0; i < orderImagesList.size(); i++) {
canvas.drawBitmap(orderImagesList.get(i), orderImagesList.get(i).getWidth() * (i % 2), orderImagesList.get(i).getHeight() * (i / 2), paint);
}
} else {
Log.e("MergeError", "Couldn't merge bitmaps");
}
return result;
}
Addition to the answer by Anton Bevza
Their library has some disadvantages that are fixed in the fork
Add dependency in app.gradle:
implementation 'com.github.martipello:MultiImageView:1.0.8.2'
Add MultiImageView to layout xml file
<com.sealstudios.multiimageview.MultiImageView
android:id="#+id/iv"
android:layout_width="100dp"
android:layout_height="100dp"
app:shape="circle" />
For setting shape of MultiImageView use attributes in layout xml file
app:shape="circle" //Circle
app:shape="rectangle" //Rectangle with round corners
app:shape="none" //Without shape
Also you can change shape by using method:
multiImageView.setShape(MultiImageView.Shape.RECTANGLE);//Rectangle with round corners
multiImageView.setShape(MultiImageView.Shape.CIRCLE);//Circle
multiImageView.setShape(MultiImageView.Shape.NONE);//Without shape
In java class find view by id:
final MultiImageView multiImageView = findViewById(R.id.iv);
For adding image to MultiImageView use method addImage(Bitmap bitmap). For example:
multiImageView.addImage(BitmapFactory.decodeResource(getResources(), R.drawable.avatar));
//or
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), ImageUri);
multiImageView.addImage(bitmap);

Categories