如何在自定义视图上单击侦听器

时间:2019-07-11 07:14:07

标签: android view

在我的一个应用程序中,我创建了具有多种颜色的圆形视图,在该视图中我想在每个颜色拱上设置点击监听器 以下是绘制该视图的图像和代码 enter image description here

自定义视图类代码

 public class CircularStatusView extends View {

    private static final float DEFAULT_PORTION_WIDTH = 10;
    private static final int DEFAULT_PORTION_SPACING = 5;
    private static final int DEFAULT_COLOR = Color.parseColor("#D81B60");
    private static final float DEFAULT_PORTIONS_COUNT = 1;
    private static final float START_DEGREE =-90;

    private float radius;
    private float portionWidth = DEFAULT_PORTION_WIDTH;
    private int portionSpacing = DEFAULT_PORTION_SPACING;
    private int portionColor = DEFAULT_COLOR;
    private float portionsCount = DEFAULT_PORTIONS_COUNT;

    private RectF mBorderRect = new RectF();
    private Paint paint;
    private SparseIntArray portionToUpdateMap = new SparseIntArray();
    private Context context;

    public CircularStatusView(Context context) {
        super(context);
        init(context, null, -1);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularStatusView, defStyle, 0);

        if (a != null) {
            portionColor = a.getColor(R.styleable.CircularStatusView_portion_color, DEFAULT_COLOR);
            portionWidth = a.getDimensionPixelSize(R.styleable.CircularStatusView_portion_width, (int) DEFAULT_PORTION_WIDTH);
            portionSpacing = a.getDimensionPixelSize(R.styleable.CircularStatusView_portion_spacing, DEFAULT_PORTION_SPACING);
            portionsCount = a.getInteger(R.styleable.CircularStatusView_portions_count, (int) DEFAULT_PORTIONS_COUNT);

            a.recycle();
        }

        paint = getPaint();

    }

    public CircularStatusView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, -1);
    }

    public CircularStatusView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs, defStyleAttr);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBorderRect.set(calculateBounds());
        radius = Math.min((mBorderRect.height() - portionWidth) / 2.0f, (mBorderRect.width() - portionWidth) / 2.0f);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float radius = this.radius;
        float center_x = mBorderRect.centerX();
        float center_y = mBorderRect.centerY();


        final RectF oval = getOval(radius, center_x, center_y);

        float degree = 360 / portionsCount;
        float percent = 100 / portionsCount;


        for (int i = 0; i < portionsCount; i++) {
            paint.setColor(getPaintColorForIndex(i));
            float startAngle = START_DEGREE + (degree * i);
            canvas.drawArc(oval, (getSpacing() / 2) + startAngle, getProgressAngle(percent) - getSpacing(), false, paint);
        }


    }

    private int getPaintColorForIndex(int i) {
        if (portionToUpdateMap.indexOfKey(i) >= 0) { //if key is exists
            return portionToUpdateMap.get(i);
        } else {
            return portionColor;
        }
    }

    @NonNull
    private RectF getOval(float radius, float center_x, float center_y) {
        final RectF oval = new RectF();
        oval.set(center_x - radius,
                center_y - radius,
                center_x + radius,
                center_y + radius);
        return oval;
    }

    @NonNull
    private Paint getPaint() {
        Paint paint = new Paint();
        paint.setColor(portionColor);
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(portionWidth);
        paint.setStrokeCap(Paint.Cap.BUTT);
        return paint;
    }

    private int getSpacing() {
        return portionsCount == 1 ? 0 : portionSpacing;
    }

    private RectF calculateBounds() {
        int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();

        int sideLength = Math.min(availableWidth, availableHeight);

        float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;
        float top = getPaddingTop() + (availableHeight - sideLength) / 2f;

        return new RectF(left, top, left + sideLength, top + sideLength);
    }

    private float getProgressAngle(float percent) {
        return percent / (float) 100 * 360;
    }

    public void setPortionsCount(int portionsCount) {
        this.portionsCount = (float) portionsCount;
    }

    public void setPortionSpacing(int spacing) {
        portionSpacing = spacing;
    }

    public void setPortionWidth(float portionWidth) {
        this.portionWidth = portionWidth;
    }

    public void setCustomPaint(Paint paint) {
        this.paint = paint;
    }

    public void setPortionsColor(int color) {
        this.portionColor = color;
        portionToUpdateMap.clear();
        invalidate();
    }

    public void setPortionColorForIndex(int index, int color) {
        if (index > portionsCount - 1) {
            throw new IllegalArgumentException("Index is Bigger than the count!");
        } else {
            Log.d("3llomi", "adding index to map " + index);
            portionToUpdateMap.put(index, color);
            invalidate();
        }
    }

}

以及我的活动课

CircularStatusView circularStatusView = findViewById(R.id.circular_status_view);
    circularStatusView.setPortionsCount(6);
    for (int i=0; i<AppConstants.outerCircleColors.length; i++){
        circularStatusView.setPortionColorForIndex(i,Color.parseColor(AppConstants.outerCircleColors[i]));

如何在此视图中的每个颜色拱上设置点击监听器?有人可以帮我吗?

3 个答案:

答案 0 :(得分:2)

您可以使用OnTouchListener从CircularStatusView中获取像素:

CircularStatusView view = ((CircularStatusView)v);
Bitmap bitmap = ((BitmapDrawable)view.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(x,y);

您可以将像素与其他颜色进行比较。喜欢...

if(pixel == Color.RED){
    //It's Red Color
 }

答案 1 :(得分:0)

由于这是单个视图,因此设置来自颜色区域的点击非常奇怪。我认为,如果可以使View具有动态创建的视图并适合多个视图,那就更好了。

除此之外,您可以尝试以下操作:https://jsfiddle.net/armakarma/h4tb7nxy/7/通过为不同的DPI设备设置(x,y)范围或为每种颜色设置绘图角度。

答案 2 :(得分:0)

您可以为onTouch事件创建接口侦听器。检查onTouch坐标。根据它们的位置,您可以将触摸的零件索引发送回接口侦听器。

虚拟代码:

public class CircularStatusView extends View {
private StatusViewTouchListener listener;
...
..
.
public void setOnClickListener(StatusViewTouchListener listener) {
  this.listener = listener;
}

public interface StatusViewTouchListener {
   public void onStatusViewTouch(int index);
}

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        int indexOfTouchedColor;
        // Check the touch points and determine in which color part it exists. 
        listener.onStatusViewTouch(indexOfTouchedColor);
        return true;
    }
}

在您使用视图的位置实现侦听器并将其设置为视图。

public class yourActivity extends Activity implements StatusViewTouchListener {

...
..
.
CircularStatusView circularStatusView = findViewById(R.id.circular_status_view);
    circularStatusView.setPortionsCount(6);
    for (int i=0; i<AppConstants.outerCircleColors.length; i++){
        circularStatusView.setPortionColorForIndex(i,Color.parseColor(AppConstants.outerCircleColors[i])); 
    circularStatusView.setOnClickListener(this);

    ...
    ..
    @Override
    public void onStatusViewTouch(int index) {
     // Perform your action based on the index of the color
    }
}