三角按钮android点击/悬停

时间:2017-08-22 14:50:26

标签: c# android xamarin

我在android中创建了一个三角形按钮。它运作良好。 我只想在悬停/按下按钮时更改填充颜色/笔触颜色(如默认按钮)。

我尝试在悬停属性更改时使视图无效,并在OnDraw方法中更改颜色但没有成功。

这是我的代码:

public enum TriangularButtonDirection
{
    Up = 0,
    Down = 1
}

class TriangularButton : Button
{
    public TriangularButton(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
        this.Initialize(null);
    }

    public TriangularButton(Context context) : base(context)
    {
        this.Initialize(null);
    }

    public TriangularButton(Context context, IAttributeSet attrs) : base(context, attrs)
    {
        this.Initialize(attrs);
    }

    public TriangularButton(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
    {
        this.Initialize(attrs);
    }

    public TriangularButton(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
    {
        this.Initialize(attrs);
    }

    private TriangularButtonDirection _direction = TriangularButtonDirection.Down;

    private void Initialize(IAttributeSet attributeSet)
    {
        if (attributeSet != null)
        {
            TypedArray a = this.Context.ObtainStyledAttributes(attributeSet, Resource.Styleable.TriangularButton);

            int direction = a.GetInt(Resource.Styleable.TriangularButton_direction, -1);
            if (direction > -1)
                this._direction = (TriangularButtonDirection)direction;
            a.Recycle();
        }
    }

    public override bool OnTouchEvent(MotionEvent e)
    {
        float x = e.GetX();
        float y = e.GetY();
        int width = this.MeasuredWidth;
        PointF point1Draw;
        PointF point2Draw;
        PointF point3Draw;
        if (this._direction == TriangularButtonDirection.Up)
        {
            point1Draw = new PointF(0, 3f * width / 4);
            point2Draw = new PointF(width, 3f * width / 4);
            point3Draw = new PointF(width / 2f, 0);
        }
        else
        {
            point1Draw = new PointF(0, 0);
            point2Draw = new PointF(width, 0);
            point3Draw = new PointF(width / 2f, 3f * width / 4);
        }
        bool test = PointInTriangle(new PointF(x, y), point1Draw, point2Draw, point3Draw);
        if (test)
            base.OnTouchEvent(e);
        return (test);
    }

    public static bool PointInTriangle(PointF p, PointF p0, PointF p1, PointF p2)
    {
        float s = p0.Y * p2.X - p0.X * p2.Y + (p2.Y - p0.Y) * p.X + (p0.X - p2.X) * p.Y;
        float t = p0.X * p1.Y - p0.Y * p1.X + (p0.Y - p1.Y) * p.X + (p1.X - p0.X) * p.Y;
        if ((s < 0) != (t < 0))
            return false;
        float a = -p1.Y * p2.X + p0.Y * (p2.X - p1.X) + p0.X * (p1.Y - p2.Y) + p1.X * p2.Y;
        if (a < 0.0)
        {
            s = -s;
            t = -t;
            a = -a;
        }
        return s > 0 && t > 0 && (s + t) <= a;
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
        this.SetMeasuredDimension(this.MeasuredWidth, 3 * this.MeasuredWidth / 4);
    }

    public override void Draw(Canvas canvas)
    {
        int width = this.MeasuredWidth;

        Paint paintFill = new Paint(PaintFlags.AntiAlias);
        paintFill.StrokeWidth = 2; 
        paintFill.Color = this.Hovered ? Color.Red : new Color(242, 180, 54);
        paintFill.SetStyle(Android.Graphics.Paint.Style.Fill);
        paintFill.AntiAlias = true;

        Paint paintStroke = new Paint(PaintFlags.AntiAlias);
        paintStroke.StrokeWidth = 2;
        paintStroke.Color = Color.White;
        paintStroke.SetStyle(Android.Graphics.Paint.Style.Stroke);
        paintStroke.AntiAlias = true;

        PointF point1Draw;
        PointF point2Draw;
        PointF point3Draw;
        if (this._direction == TriangularButtonDirection.Up)
        {
            point1Draw = new PointF(0, 3f * width / 4);
            point2Draw = new PointF(width, 3f * width / 4);
            point3Draw = new PointF(width / 2f, 0);
        }
        else
        {
            point1Draw = new PointF(0, 0);
            point2Draw = new PointF(width, 0);
            point3Draw = new PointF(width / 2f, 3f * width / 4);
        }

        Path path = new Path();
        path.SetFillType(Path.FillType.EvenOdd);
        path.MoveTo(point1Draw.X, point1Draw.Y);
        path.LineTo(point2Draw.X, point2Draw.Y);
        path.LineTo(point3Draw.X, point3Draw.Y);
        path.LineTo(point1Draw.X, point1Draw.Y);
        path.Close();

        canvas.DrawPath(path, paintFill);
        canvas.DrawPath(path, paintStroke);
    }
}

编辑:最终代码

    class TriangularButton : Button
{
    public TriangularButton(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
        this.Initialize(null);
    }

    public TriangularButton(Context context) : base(context)
    {
        this.Initialize(null);
    }

    public TriangularButton(Context context, IAttributeSet attrs) : base(context, attrs)
    {
        this.Initialize(attrs);
    }

    public TriangularButton(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
    {
        this.Initialize(attrs);
    }

    public TriangularButton(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
    {
        this.Initialize(attrs);
    }

    private TriangularButtonDirection _direction = TriangularButtonDirection.Down;
    private TriangularButtonState _state = TriangularButtonState.Normal;
    private Paint _paintFillNormal;
    private Paint _paintStrokeNormal;
    private Paint _paintFillPressed;
    private Paint _paintStrokePressed;
    private void Initialize(IAttributeSet attributeSet)
    {
        if (attributeSet != null)
        {
            TypedArray a = this.Context.ObtainStyledAttributes(attributeSet, Resource.Styleable.TriangularButton);

            int direction = a.GetInt(Resource.Styleable.TriangularButton_direction, -1);
            if (direction > -1)
                this._direction = (TriangularButtonDirection)direction;
            a.Recycle();
        }

        this._paintFillNormal = new Paint(PaintFlags.AntiAlias);
        this._paintFillNormal.StrokeWidth = 2;
        this._paintFillNormal.Color = new Color(242, 180, 54);
        this._paintFillNormal.SetStyle(Android.Graphics.Paint.Style.Fill);
        this._paintFillNormal.AntiAlias = true;

        this._paintFillPressed = new Paint(PaintFlags.AntiAlias);
        this._paintFillPressed.StrokeWidth = 2;
        this._paintFillPressed.Color = new Color(255, 255, 255, 51);
        this._paintFillPressed.SetStyle(Android.Graphics.Paint.Style.Fill);
        this._paintFillPressed.AntiAlias = true;


        this._paintStrokeNormal = new Paint(PaintFlags.AntiAlias);
        this._paintStrokeNormal.StrokeWidth = 2;
        this._paintStrokeNormal.Color = Color.White;
        this._paintStrokeNormal.SetStyle(Android.Graphics.Paint.Style.Stroke);
        this._paintStrokeNormal.AntiAlias = true;

        this._paintStrokePressed = new Paint(PaintFlags.AntiAlias);
        this._paintStrokePressed.StrokeWidth = 2;
        this._paintStrokePressed.Color = new Color(51, 51, 51, 51);
        this._paintStrokePressed.SetStyle(Android.Graphics.Paint.Style.Stroke);
        this._paintStrokePressed.AntiAlias = true;



    }

    private bool _isEnabled;
    public override bool Enabled
    {
        get => this._isEnabled;
        set
        {
            if (this._isEnabled != value)
            {
                this._isEnabled = value;
                this.Invalidate();
            }
        }
    }

    public override bool OnTouchEvent(MotionEvent e)
    {
        if (!this._isEnabled)
            return (false);
        float x = e.GetX();
        float y = e.GetY();
        int width = this.MeasuredWidth;
        PointF point1Draw;
        PointF point2Draw;
        PointF point3Draw;
        if (this._direction == TriangularButtonDirection.Up)
        {
            point1Draw = new PointF(0, 3f * width / 4);
            point2Draw = new PointF(width, 3f * width / 4);
            point3Draw = new PointF(width / 2f, 0);
        }
        else
        {
            point1Draw = new PointF(0, 0);
            point2Draw = new PointF(width, 0);
            point3Draw = new PointF(width / 2f, 3f * width / 4);
        }
        bool test = PointInTriangle(new PointF(x, y), point1Draw, point2Draw, point3Draw);
        if (test)
        {
            base.OnTouchEvent(e);
        }
        switch (e.Action)
        {
            case MotionEventActions.Down:
                this._state = TriangularButtonState.Pressed;
                test = true;
                this.Invalidate();
                break;

            case MotionEventActions.HoverEnter:
                this._state = TriangularButtonState.Hovered;
                this.Invalidate();
                break;

            case MotionEventActions.Up:
                this._state = TriangularButtonState.Normal;
                this.Invalidate();
                break;
            case MotionEventActions.HoverExit:
                this._state = TriangularButtonState.Normal;
                this.Invalidate();
                break;
        }
        return (test);
    }

    public static bool PointInTriangle(PointF p, PointF p0, PointF p1, PointF p2)
    {
        float s = p0.Y * p2.X - p0.X * p2.Y + (p2.Y - p0.Y) * p.X + (p0.X - p2.X) * p.Y;
        float t = p0.X * p1.Y - p0.Y * p1.X + (p0.Y - p1.Y) * p.X + (p1.X - p0.X) * p.Y;
        if ((s < 0) != (t < 0))
            return false;
        float a = -p1.Y * p2.X + p0.Y * (p2.X - p1.X) + p0.X * (p1.Y - p2.Y) + p1.X * p2.Y;
        if (a < 0.0)
        {
            s = -s;
            t = -t;
            a = -a;
        }
        return s > 0 && t > 0 && (s + t) <= a;
    }

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
        this.SetMeasuredDimension(this.MeasuredWidth, 3 * this.MeasuredWidth / 4);
    }

    public override void Draw(Canvas canvas)
    {
        int width = this.MeasuredWidth;

        PointF point1Draw;
        PointF point2Draw;
        PointF point3Draw;
        if (this._direction == TriangularButtonDirection.Up)
        {
            point1Draw = new PointF(0, 3f * width / 4);
            point2Draw = new PointF(width, 3f * width / 4);
            point3Draw = new PointF(width / 2f, 0);
        }
        else
        {
            point1Draw = new PointF(0, 0);
            point2Draw = new PointF(width, 0);
            point3Draw = new PointF(width / 2f, 3f * width / 4);
        }

        Path path = new Path();
        path.SetFillType(Path.FillType.EvenOdd);
        path.MoveTo(point1Draw.X, point1Draw.Y);
        path.LineTo(point2Draw.X, point2Draw.Y);
        path.LineTo(point3Draw.X, point3Draw.Y);
        path.LineTo(point1Draw.X, point1Draw.Y);
        path.Close();
        if (!this.Enabled)
        {
            canvas.DrawPath(path, this._paintStrokeNormal);
        }
        else
        {
            canvas.DrawPath(path, this._state == TriangularButtonState.Normal ? this._paintFillNormal : this._paintFillPressed);
            canvas.DrawPath(path, this._state == TriangularButtonState.Normal ? this._paintStrokeNormal : this._paintStrokePressed);
        }
    }
}

感谢您的帮助

1 个答案:

答案 0 :(得分:2)

  

是的,我使用的是Xamarin.Android。我可以自定义按钮,但我无法获得所需的结果。样式文件无法使用带边框的三角形...

仅从你的代码中,我认为你的&#34;带边框的三角形&#34;表示三角形按钮笔划,然后您可以使用可绘制资源文件创建它,例如,为正常,按下和悬停状态创建三个drawable:

正常(三角形的代码来自this blog):

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
    <rotate
        android:fromDegrees="45"
        android:toDegrees="45"
        android:pivotX="-40%"
        android:pivotY="87%">
      <shape
          android:shape="rectangle">
        <stroke android:color="#800000" android:width="5dp" />
        <solid
            android:color="#ee9ca8" />
      </shape>
    </rotate>
  </item>
</layer-list>

&#34;代码#34;和#34;专注&#34;状态是一样的,我只是改变了笔画的颜色和实体。

然后你可以用这样的选择器应用这个drawable:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true"
        android:drawable="@drawable/triangleClick" />
  <!-- pressed -->
  <item android:state_focused="true"
        android:drawable="@drawable/triangleHover" />
  <!-- focused -->
  <item android:drawable="@drawable/triangleNormal" />
  <!-- default -->
</selector>

最后像这样使用这个选择器:

<Button android:layout_height="70dp"
        android:layout_width="70dp"
        android:layout_gravity="center_horizontal"
        android:background="@drawable/triangleSelector"
        style="?android:attr/borderlessButtonStyle" />

检查我的演示结果(状态顺序为:normal-&gt; pressed-&gt; hovered):

enter image description here

更新

你可以让三方这样抚摸:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
    <rotate
        android:fromDegrees="45"
        android:toDegrees="45"
        android:pivotX="-40%"
        android:pivotY="87%">
      <shape
          android:shape="rectangle">
        <stroke android:color="#800000" android:width="5dp" />
        <solid
            android:color="#ee9ca8" />
      </shape>
    </rotate>
  </item>
  <item android:top="65dp" android:right="5dp" android:left="5dp">
    <shape android:shape="rectangle">
      <solid android:color="#800000" />
    </shape>
  </item>
</layer-list>

您可以计算边距以使其更美观,只是想在此图层中添加其他项目。

更新2:

除了我在评论中写的方法,为了继续你在自定义按钮类中这样做的工作,你可以像这样编码:

public override bool OnTouchEvent(MotionEvent e)
{
    float x = e.GetX();
    float y = e.GetY();
    int width = this.MeasuredWidth;
    PointF point1Draw;
    PointF point2Draw;
    PointF point3Draw;
    if (this._direction == TriangularButtonDirection.Up)
    {
        point1Draw = new PointF(0, 3f * width / 4);
        point2Draw = new PointF(width, 3f * width / 4);
        point3Draw = new PointF(width / 2f, 0);
    }
    else
    {
        point1Draw = new PointF(0, 0);
        point2Draw = new PointF(width, 0);
        point3Draw = new PointF(width / 2f, 3f * width / 4);
    }

    bool test = PointInTriangle(new PointF(x, y), point1Draw, point2Draw, point3Draw);
    if (test)
        base.OnTouchEvent(e);

    switch (e.Action)
    {
        case MotionEventActions.Down:
            mstate = state.pressed;
            this.Invalidate();
            break;

        case MotionEventActions.HoverEnter:
            mstate = state.hovered;
            this.Invalidate();
            break;

        case MotionEventActions.Up:
            mstate = state.normal;
            this.Invalidate();
            break;

        case MotionEventActions.HoverExit:
            mstate = state.normal;
            this.Invalidate();
            break;
    }

    return (test);
}

private state mstate = state.normal;

private enum state
{
    normal,
    pressed,
    hovered
}

public static bool PointInTriangle(PointF p, PointF p0, PointF p1, PointF p2)
{
    float s = p0.Y * p2.X - p0.X * p2.Y + (p2.Y - p0.Y) * p.X + (p0.X - p2.X) * p.Y;
    float t = p0.X * p1.Y - p0.Y * p1.X + (p0.Y - p1.Y) * p.X + (p1.X - p0.X) * p.Y;
    if ((s < 0) != (t < 0))
        return false;
    float a = -p1.Y * p2.X + p0.Y * (p2.X - p1.X) + p0.X * (p1.Y - p2.Y) + p1.X * p2.Y;
    if (a < 0.0)
    {
        s = -s;
        t = -t;
        a = -a;
    }
    return s > 0 && t > 0 && (s + t) <= a;
}

protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
    base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
    this.SetMeasuredDimension(this.MeasuredWidth, 3 * this.MeasuredWidth / 4);
}

public override void Draw(Canvas canvas)
{
    int width = this.MeasuredWidth;
    switch (mstate)
    {
        case state.normal:
            Paint paintFill = new Paint(PaintFlags.AntiAlias);
            paintFill.StrokeWidth = 2;
            paintFill.Color = this.Hovered ? Color.Red : new Color(242, 180, 54);
            paintFill.SetStyle(Android.Graphics.Paint.Style.Fill);
            paintFill.AntiAlias = true;

            Paint paintStroke = new Paint(PaintFlags.AntiAlias);
            paintStroke.StrokeWidth = 2;
            paintStroke.Color = Color.White;
            paintStroke.SetStyle(Android.Graphics.Paint.Style.Stroke);
            paintStroke.AntiAlias = true;

            PointF point1Draw;
            PointF point2Draw;
            PointF point3Draw;
            if (this._direction == TriangularButtonDirection.Up)
            {
                point1Draw = new PointF(0, 3f * width / 4);
                point2Draw = new PointF(width, 3f * width / 4);
                point3Draw = new PointF(width / 2f, 0);
            }
            else
            {
                point1Draw = new PointF(0, 0);
                point2Draw = new PointF(width, 0);
                point3Draw = new PointF(width / 2f, 3f * width / 4);
            }

            Path path = new Path();
            path.SetFillType(Path.FillType.EvenOdd);
            path.MoveTo(point1Draw.X, point1Draw.Y);
            path.LineTo(point2Draw.X, point2Draw.Y);
            path.LineTo(point3Draw.X, point3Draw.Y);
            path.LineTo(point1Draw.X, point1Draw.Y);
            path.Close();

            canvas.DrawPath(path, paintFill);
            canvas.DrawPath(path, paintStroke);
            break;

        case state.hovered:
            //TODO:
            break;

        case state.pressed:
            //TODO:
            break;
    }
}