我有一个看起来像这样的单身图像
我需要做的是区分对身体不同部位的点击。
例如,如果单击头部,则应执行函数onHeadClicked
。如果我单击左侧,则单击一个函数onLeftHandClicked
。这将如何运作?
答案 0 :(得分:1)
首先,您必须将实体点的坐标存储在实际图像中。然后只需检查点击坐标是否在身体点的坐标内。您还应确保使用imageview的矩阵及其在屏幕上的坐标来缩放点
例如,如果
class BodyPoint{
String name;
int x;
int y;
public(String name,int x,int y){
this.name = name;
this.x = x;
this.y = y;}
}
BodyPoint headCoordinates = new BodyPoint ("head",50,20);
BodyPoint neckCoordinates = new BodyPoint ("neck",50,50);
BodyPoint leftHandCoordinates = new BodyPoint ("leftHand",10,50);
BodyPoint rightHandCoordinates = new BodyPoint ("rightHand",80,50);
BodyPoint[] bodyCoordinates = new BodyPoint[]{headCoordinates,neckCoordinates,
leftHandCoordinates ,rightHandCoordinates };
yourImgView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int[] viewCoords = new int[2];
yourImgView.getLocationOnScreen(viewCoords);
int touchX = (int) event.getX();
int touchY = (int) event.getY();
int imageX = touchX - viewCoords[0]; // viewCoords[0] is the X coordinate
int imageY = touchY - viewCoords[1];
Matrix mMatrix = getImageMatrix();
float[] f = new float[9];
mMatrix .getValues(f);
float scaleX = f[Matrix.MSCALE_X];
float scaleY = f[Matrix.MSCALE_Y];
processTouchedPoints(imageX/(int)scaleX , imageY/(int)scaleY );
return true;
}
});
...
int range = 50;
void processTouchedPoints(int imageX,int imageY){
foreach(BodyPoint mBodyPoint:bodyCoordinates ){
int x = mBodyPoint.x;
int y = mBodyPoint.y;
if((imageX> (x-range) && imageX<(x+range))
&&(imageY> (y-range) && imageY<(y+range))){
doWhatever(mBodyPoint.name)
}
}
}
答案 1 :(得分:1)
警告:此解决方案至少有5年(我还在使用它),所以肯定已经过时了,也许有新技术可以解决这个问题。无论如何,我会在这里发布解决方案以帮助您。此外,这个解决方案有点麻烦,你可以重构或改进它,随意做。
此解决方案基于2个图像,其中一个图像将可见(您要向用户显示哪个图像),另一个图像将不可见。
不可见图像必须具有与目标图像相同的像素大小(在您的情况下是身体图像),将是透明的(或黑色背景),并且您将要点击的不同区域填充不同的颜色。< / p>
因此,当您单击目标图像时,将检查其矩阵的坐标,然后从该坐标开始,从第二个图像中获取按下的像素的颜色。
由于您知道哪种颜色与身体的哪个部分相对应(因为您之前已经使用color-&gt; part_of_body配置了地图),因此获取一种颜色就可以确切地知道身体的一部分被点击。
您有目标图片:
然后,您需要创建第二个图像,如下所示:
看到你现在身体的每个部位都标有明显的颜色。请注意,颜色明显不同。这就是为什么如果你使用相似的颜色,当时可能会有冲突来检索身体的一部分,因为颜色可能会混淆。
之后,您需要使用透明背景导出颜色图像,您应该得到以下内容(请注意背景是透明的,但StackOverflow的背景是白色的):
您将使用第一张和第三张图片,第二张图片只是一个中间步骤。
首先,您必须在代码中配置您的地图颜色 - &gt; part_of_body:
public HashMap<Integer, String> bodyParts;
bodyParts.put(parseColor("#ff0000"), "part_1");
bodyParts.put(parseColor("#00ff00"), "part_2");
bodyParts.put(parseColor("#0000ff"), "part_3");
bodyParts.put(parseColor("#ffff00"), "part_4");
... // Finish here with all your parts and colors
然后我制作了自定义ImageView
,以便更轻松地处理图片:
<强> ZoneTapImageView.java 强>
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import java.util.HashMap;
import uk.co.senab.photoview.PhotoViewAttacher;
public class ZoneTapImageView extends FrameLayout implements PhotoViewAttacher.OnPhotoTapListener {
private static final String LOG_TAG = "ZoneMapTouch";
private static final int DEFAULT_TOLERANCE = 25;
private ImageView imageView;
private ImageView imageViewAreas;
@SuppressLint("UseSparseArrays")
private HashMap<Integer, String> areasMap = new HashMap<>();
private Context context;
private OnAreaObtainedListener areaObtainedListener;
private PhotoViewAttacher imageViewAttacher;
private PhotoViewAttacher imageViewAreasAttacher;
public ZoneTapImageView(Context context) {
super(context);
init(context);
}
public ZoneTapImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZoneTapImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
int padding = getResources().getDimensionPixelSize(R.dimen.groups_padding_mini);
this.context = context;
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
this.setLayoutParams(params);
params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER;
imageView = new ImageView(getContext());
imageView.setPadding(padding, padding, padding, padding);
imageView.setLayoutParams(params);
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageView.setAdjustViewBounds(true);
imageViewAreas = new ImageView(getContext());
imageViewAreas.setPadding(padding, padding, padding, padding);
imageViewAreas.setLayoutParams(params);
imageViewAreas.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageViewAreas.setAdjustViewBounds(true);
imageViewAreas.setVisibility(View.INVISIBLE);
this.addView(imageViewAreas);
this.addView(imageView);
}
public void setImageResources(int resIdImage, int resIdImageAreas) {
setImageResource(resIdImage);
setImageResourceAreas(resIdImageAreas);
}
public void setImageResource(final int resIdImage) {
imageView.post(new Runnable() {
@Override
public void run() {
// Here I use a Image Cache, but it's not necessary
ImageMemoryCache.loadBitmap(context, resIdImage, imageView, imageView.getWidth(), imageView.getHeight(), new ImageMemoryCache.OnImageLoadedListener() {
@Override
public void onImageLoaded() {
if (imageViewAttacher == null) {
imageViewAttacher = new PhotoViewAttacher(imageView);
imageViewAttacher.setZoomable(true);
imageViewAttacher.setOnPhotoTapListener(ZoneTapImageView.this);
}
}
});
}
});
}
public void setImageResourceAreas(final int resIdImageAreas) {
imageViewAreas.post(new Runnable() {
@Override
public void run() {
// Here I use a Image Cache, but it's not necessary
ImageMemoryCache.loadBitmap(context, resIdImageAreas, imageViewAreas, imageViewAreas.getWidth(), imageViewAreas.getHeight(), new ImageMemoryCache.OnImageLoadedListener() {
@Override
public void onImageLoaded() {
if (imageViewAreasAttacher == null) {
imageViewAreasAttacher = new PhotoViewAttacher(imageViewAreas);
imageViewAreasAttacher.setZoomable(false);
}
}
});
}
});
}
public void setZoomOut() {
if (imageViewAttacher != null)
imageViewAttacher.setScale(1, true);
}
public void setOnAreaObtainedListener(OnAreaObtainedListener areaObtainedListener) {
this.areaObtainedListener = areaObtainedListener;
}
@Override
public void onPhotoTap(View view, float x, float y) {
if (imageViewAreasAttacher == null) return;
final RectF displayRect = imageViewAreasAttacher.getDisplayRect();
float xAbsolute = x * displayRect.width() + displayRect.left;
float yAbsolute = y * displayRect.height() + displayRect.top;
Log.d("MapTouch", "X: " + xAbsolute + " Y: " + yAbsolute);
getAreaFromCoordinatesAsync((int) xAbsolute, (int) yAbsolute, areaObtainedListener);
}
public void setAreasMap(HashMap<Integer, String> areasMap) {
this.areasMap = areasMap;
}
public void getAreaFromCoordinatesAsync(final int x, final int y, final OnAreaObtainedListener onAreaObtainedListener) {
new Thread(new Runnable() {
@Override
public void run() {
String area = getAreaFromCoordinates(x, y);
if (onAreaObtainedListener != null) {
onAreaObtainedListener.OnArea(area);
}
}
}).start();
}
public String getAreaFromCoordinates(int x, int y) {
int touchColor = getTapColor(x, y);
Log.d(LOG_TAG, "Color (" + x + ", " + y + "): " + touchColor);
if (touchColor == Integer.MIN_VALUE) return null;
return getAreaFromColor(touchColor);
}
public String getAreaFromColor(int color) {
for (Integer colorKey : areasMap.keySet()) {
if (matchColor(colorKey, color, DEFAULT_TOLERANCE)) {
return areasMap.get(colorKey);
}
}
return null;
}
private boolean matchColor(int color1, int color2, int tolerance) {
if (Math.abs(Color.red(color1) - Color.red(color2)) > tolerance)
return false;
if (Math.abs(Color.green(color1) - Color.green(color2)) > tolerance)
return false;
if (Math.abs(Color.blue(color1) - Color.blue(color2)) > tolerance)
return false;
return true;
}
private int getTapColor(int x, int y) {
try {
// Convert coordinates for scaled bitmap
float[] eventXY = new float[]{x, y};
Matrix invertMatrix = new Matrix();
imageViewAreas.getImageMatrix().invert(invertMatrix);
invertMatrix.mapPoints(eventXY);
x = (int) eventXY[0];
y = (int) eventXY[1];
// Get bitmap
Drawable imgDrawable = imageViewAreas.getDrawable();
Bitmap bitmap = ((BitmapDrawable) imgDrawable).getBitmap();
// Get color
return bitmap.getPixel(x, y);
} catch (Exception e) {
return Integer.MIN_VALUE;
}
}
}
您需要以下依赖才能使其正常运行:
compile 'com.github.chrisbanes.photoview:library:1.2.2'
要实例化上一个类,您可以按如下方式执行:
imageView = new ZoneTapImageView(getActivity());
imageView.setImageResources(R.drawable.body_image, R.drawable.invisielb_areas_image);
imageView.setAreasMap(bodyParts);
imageView.setOnAreaObtainedListener(new OnAreaObtainedListener() {
@Override
public void OnArea(final String area) {
Log.d("MapTouch", "Area: " + area);
// Area here is such "part_1" or "part_2"
if (area != null) {
// Handle your bodyPart click
}
}
});
这就是全部。希望我没有错过任何代码,并希望这对你有所帮助。