据我所知(现在很少),Android中的所有视图都有方形或矩形形状。这几乎一直很好,直到你想要 - 我真正想要的 - 创建可以处理事件的非方形形状。
我的目标是将一个圆圈分成3个120°的部分。圆的每个部分应该像按钮一样。问题是,如果我们查看一个圆圈的3个并将它们放在一个严格包含它们的方框中,它们会相互重叠:不知道用户想要点击哪个...
我尝试使用自定义视图,其中我绘制了我的部分,但事件在视图的所有表面上都会触发。
非常欢迎任何建议或指示。
谢谢,保罗
答案 0 :(得分:2)
我认为处理此问题的方法是覆盖每个控件上的onTouch
,对触摸坐标执行自己的几何检查,如果它位于自定义区域return false
之外,它将通过事件另一种观点。否则返回调用方法的超级版本。我不是百分百肯定所以有人请你纠正我,如果我错了,但值得一试。
答案 1 :(得分:2)
我不知道你是否可以明确地创建这些形状,但肯定会有一种方法在自定义视图中使用它。但这很难。
首先,您需要通过设置OnTouch
,更多here来挂钩OnTouchListener
事件。最简单的方法是仅对ACTION_UP
的{{1}}操作做出反应,可通过MotionEvent
访问here上的详细信息。在MotionEvent.getAction()
中,您可以获得X和Y坐标,其中事件通过MotionEvent
和getX()
发生。
现在开始数学...你现在必须计算点击发生的部分。要做到这一点,你需要自定义视图的大小(以像素为单位)及其位置(左上角),我恐怕现在无法告诉你相应的方法......你必须把它们挖出来......假设圆的中心始终位于视图的中心,圆圈完全延伸到视图边界,您现在可以计算扇区。
让我们分别调用事件X和Y坐标getY()
和eventX
,让eventY
和centerX
成为圆心坐标以及centerY
圆圈半径。
首先检查是否在圆圈中发生事件,然后计算角度:
radius
最后,int deltaX = eventX - centerX;
int deltaY = eventY - centerY;
if (Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)) > radius) {
// out of circle!
}
// offset for radiant, depending on quadrant
double offset = 0;
if (deltaX > 0 && deltaY < 0) {
// top right -> nothing to do
} else if (deltaX > 0 && deltaY > 0) {
// bottom right -> add 90 degrees
offset = Math.PI/2;
} else if (deltaX < 0 && deltaY > 0) {
// bottom left -> add 180 degrees
offset = Math.PI;
} else if (deltaX < 0 && deltaY < 0) {
// top left -> add 270 degrees
offset = Math.PI * 3/2;
}
//now calculate angle
double angle = Math.asin(deltaY / deltaX);
double total = angle + offset;
应为顺时针角度,您可以根据您的部分检查辐射中的点击次数;)如果出现问题,请纠正我^^
答案 2 :(得分:2)
首先,非常感谢您提供的有助于我实现目标的所有建议。
由于无法在形状上触发事件,因此在包含形状的视图上使用onTouch()是可行的方法。
以下,您需要运行它。
首先,自定义视图Zones.java:
package com.vector;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class Zones extends View {
RectF rectf = new RectF(0, 0, 300, 300);
Paint paint = new Paint();
Canvas canvas = null;
Integer zone = 0;
// important: do not forget to add AttributeSet, it is necessary to have this
// view called from an xml view file
public Zones(Context context, AttributeSet attributeset) {
super(context, attributeset);
this.setBackgroundColor(0xFF207CA1);
}
@Override
protected void onDraw(Canvas canvas) {
// set layout of the view
layout(0, 0, 300, 300);
// expose canvas at view level
this.canvas = canvas;
// check for zone 1 to 3
if(zone >= 1 && zone <= 3)
{
drawTouchZones(zone);
}
}
protected void drawTouchZones(Integer zone)
{
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
paint.setAlpha(75);
Path path = new Path();
if(zone == 1) {
path.moveTo(150,150);
path.lineTo(150,0);
path.arcTo(rectf, 270, 120);
path.close();
} else if(zone == 2) {
path.moveTo(150,150);
path.arcTo(rectf, 30, 120);
path.lineTo(150,150);
path.close();
} else if(zone == 3) {
path.moveTo(150,0);
path.lineTo(150,150);
path.arcTo(rectf, 150, 120);
path.close();
}
canvas.drawPath(path, paint);
}
}
二,主要活动,Design.java:
package com.vector;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class Design extends Activity {
/** Called when the activity is first created. */
private Zones v;
protected Integer zone = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
// get our custom view
setContentView(R.layout.main);
v = (Zones) findViewById(R.id.zone);
// add onClick Listener
v.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Log.i("zone clicked", "" + zone);
// tell to our view which zone has been clicked
v.zone = zone;
// invalidate to call onDraw method of the custom view and draw the zone
v.invalidate();
}
});
v.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
zone = getZone(event);
return false;
}
});
}
catch(Exception e)
{
Log.e("e", e.getMessage());
}
}
// detect clicked zone through MotionEvent
public int getZone(MotionEvent e)
{
Float x = e.getX();
Float y = e.getY();
// 0:00 to 4:00
if((x > 150 && x < 300 && y < 150) ||
(x > 150 && x < 300 && y > 150 && (x - 150) / (y - 150) > 1.5))
{
return 1;
}
// 4:00 to 8:00
else if((x >= 150 && x < 300 & y > 150 && (x - 150) / (y - 150) < 1.5) ||
(x > 0 && x < 150 && y > 150 && (150 - x) / (y - 150) < 1.5))
{
return 2;
}
// 8:00 to 0:00
else
{
return 3;
}
}
}
...和主xml视图(嵌入我们的自定义类视图)main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.vector.Zones android:id="@+id/zone" android:layout_height="wrap_content" android:layout_width="wrap_content">
</com.vector.Zones>
</LinearLayout>
任何评论都表示赞赏! 保罗:)