android不规则图形控件显示背景图片以及点击效果,多边形控件实例

我们在开发应用的过程中,经常会遇见美术突发奇想,给你来个狂拽酷炫效果的情况。下面我们就来说一下多边形控件,以及他的点击。

先上图

一、首先定义各种图形

1.菱形

public class DiamondView extends ImageView {
    private Context mContext;
    private int mWidth;
    private int mHeight;

    // 以上方角点所在的点位置为模式名
    public static final int TYPE_LEFT_TOP = 0;

    private int mMode;
    private int mColor;
    private String mText;
    // 四个点的顺序,从leftTop开始计算,顺时针数过去,依次四个点
    private int mPointOne[];
    private int mPointTwo[];
    private int mPointThree[];
    private int mPointFour[];

    private Path mPath;
    private Paint mPaint;

    private boolean isClicked = false; //是否被按下

    public DiamondView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        mPath = new Path();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mColor = Color.parseColor("#FFFFFF");
        mPaint.setColor(mColor);
    }

    public void setMode(int model) {
        mMode = model;
        postInvalidate();
    }

    public void setColor(int color) {
        mColor = color;
        postInvalidate();
    }

    public void setText(String text) {
        mText = text;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.clipPath(mPath, Region.Op.INTERSECT);
        super.onDraw(canvas);
        if(!isClicked) {
            mPaint.setColor(Color.argb(180, 0, 0, 0));
            canvas.drawPath(mPath, mPaint);
        }
        if(mText != null) {
            mPaint.setFakeBoldText(true);
            mPaint.setTextSize(sp2px(mContext,13));
            mPaint.setColor(mColor);
            float tw = mPaint.measureText(mText);
            float th = mPaint.measureText(mText)/mText.length();
            switch (mMode) {
                case TYPE_LEFT_TOP:
                    canvas.drawText(mText, (mWidth - tw)/2f, (mHeight+th)/2f, mPaint);
                    break;
            }
        }
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
        super.onSizeChanged(width, height, oldw, oldh);
        mWidth = width;
        mHeight = height;
        switch (mMode) {
            case TYPE_LEFT_TOP:
                mPointOne = new int[] { 0, 0 };
                mPointTwo = new int[] { width*140/250, 0 };
                mPointThree = new int[] { width, height };
                mPointFour = new int[] { width*110/250, height };
                break;
        }

        if (null != mPointOne) {
            mPath.moveTo(mPointOne[0], mPointOne[1]);
            mPath.lineTo(mPointTwo[0], mPointTwo[1]);
            mPath.lineTo(mPointThree[0], mPointThree[1]);
            mPath.lineTo(mPointFour[0], mPointFour[1]);
            mPath.close();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        RectF bounds = new RectF();
        mPath.computeBounds(bounds, true);
        Region region = new Region();
        region.setPath(mPath, new Region((int)bounds.left, (int)bounds.top,(int)bounds.right, (int)bounds.bottom));
        boolean ct =  region.contains((int)event.getX(), (int)event.getY());

        if(event.getAction() == MotionEvent.ACTION_DOWN){
            if(ct){
                isClicked = true;
                invalidate();
                return true;
            }
            return false;
        }else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL){
            if(isClicked){
                isClicked = false;
                invalidate();
                if (null != mOnClickListener && ct && event.getAction() != MotionEvent.ACTION_CANCEL) {
                    mOnClickListener.onClick(this);
                    return true;
                }
            }
            return false;
        }else if(event.getAction() == MotionEvent.ACTION_MOVE){
            return isClicked;
        }
        return super.onTouchEvent(event);
    }

    private OnClickListener mOnClickListener;
    public void setOnViewClickListener(OnClickListener clickListener){
        mOnClickListener = clickListener;
    }

    //计算两点的距离
    private int distance(PointF point1, PointF point2) {
        int disX = (int) Math.abs(point1.x - point2.x);
        int disY = (int) Math.abs(point1.y - point2.y);
        return (int) Math.sqrt(Math.pow(disX, 2) + Math.pow(disY, 2));
    }

    //将sp值转换为px值,保证文字大小不变
    public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

}

绘制图形主要依靠Path来定义四个点,围成一个菱形。在ondraw的时候再调用

canvas.clipPath(mPath, Region.Op.INTERSECT);来切割画布,使得图片显示范围也在菱形内。
点击的时候靠的是Region 和path配合使用,判断点击的点是否在path勾勒的范围内,从而控制触摸事件。
 
 
除了菱形以外,还有其他的形状的类,代码太多不一一列举,文章结尾会附带完整项目包。
 
各种形状定义好之后就是排布
 
先写在xml布局文件中
 
<com.example.lupingshenqi.QiQiaoLayout android:id="@+id/activity_main_qiqiaolayout"  android:orientation="vertical"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:background="@color/white"  android:padding="10dp"> <com.example.lupingshenqi.TriangleView  android:id="@+id/classify_1"  android:layout_width="100dp"  android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView  android:id="@+id/classify_2"  android:layout_width="100dp"  android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView  android:id="@+id/classify_3"  android:layout_width="100dp"  android:layout_height="100dp" /> <com.example.lupingshenqi.DiamondView  android:id="@+id/classify_4"  android:layout_width="100dp"  android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView  android:id="@+id/classify_5"  android:layout_width="100dp"  android:layout_height="100dp" /> <com.example.lupingshenqi.SquareView  android:id="@+id/classify_6"  android:layout_width="100dp"  android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView  android:id="@+id/classify_7"  android:layout_width="100dp"  android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView  android:id="@+id/classify_8"  android:layout_width="100dp"  android:layout_height="100dp" /> </com.example.lupingshenqi.QiQiaoLayout>

然后是在onSizeChanged的时候进行重新排布

 
 
public class QiQiaoLayout extends RelativeLayout{ private ArrayList<CategoryBean> mClassifyList = new ArrayList<>(); public QiQiaoLayout(Context context, AttributeSet attrs) { super(context, attrs); } public void setDate(ArrayList<CategoryBean> list){ mClassifyList.clear(); if(list!=null){ mClassifyList.addAll(list); } if(mClassifyList!=null){ for (int i=0;i<mClassifyList.size() && i<getChildCount();i++) { CategoryBean bean = mClassifyList.get(i); if(getChildAt(i) instanceof TriangleView){ TriangleView view = (TriangleView)getChildAt(i); GlideImageLoadUtils.displayImage(getContext(), bean.categoryIconUrl, view, GlideImageLoadUtils.getIconNormalOptions()); view.setText(bean.categoryName); view.setOnViewClickListener(new OnClickListener() { @Override  public void onClick(View view) { Toast.makeText(getContext(),"点击了按钮!",Toast.LENGTH_SHORT).show(); } }); }else if(getChildAt(i) instanceof DiamondView) { DiamondView view = (DiamondView)getChildAt(i); GlideImageLoadUtils.displayImage(getContext(), bean.categoryIconUrl, view, GlideImageLoadUtils.getIconNormalOptions()); view.setText(bean.categoryName); view.setOnViewClickListener(new OnClickListener() { @Override  public void onClick(View view) { Toast.makeText(getContext(),"点击了按钮!",Toast.LENGTH_SHORT).show(); } }); }else if(getChildAt(i) instanceof SquareView) { SquareView view = (SquareView)getChildAt(i); GlideImageLoadUtils.displayImage(getContext(), bean.categoryIconUrl, view, GlideImageLoadUtils.getIconNormalOptions()); view.setText(bean.categoryName); view.setOnViewClickListener(new OnClickListener() { @Override  public void onClick(View view) { Toast.makeText(getContext(),"点击了按钮!",Toast.LENGTH_SHORT).show(); } }); } } } postInvalidate(); } @Override  protected void onFinishInflate() { super.onFinishInflate(); TriangleView mClassifyView1 = (TriangleView) findViewById(R.id.classify_1); mClassifyView1.setMode(TriangleView.TYPE_LEFT_TOP); TriangleView mClassifyView2 = (TriangleView) findViewById(R.id.classify_2); mClassifyView2.setMode(TriangleView.TYPE_RIGHT_BOTTOM); TriangleView mClassifyView3 = (TriangleView) findViewById(R.id.classify_3); mClassifyView3.setMode(TriangleView.TYPE_RIGHT_MIDDLE); DiamondView mClassifyView4 = (DiamondView) findViewById(R.id.classify_4); mClassifyView4.setMode(DiamondView.TYPE_LEFT_TOP); TriangleView mClassifyView5 = (TriangleView) findViewById(R.id.classify_5); mClassifyView5.setMode(TriangleView.TYPE_RIGHT_BOTTOM_SMAILL); SquareView mClassifyView6 = (SquareView) findViewById(R.id.classify_6); TriangleView mClassifyView7 = (TriangleView) findViewById(R.id.classify_7); mClassifyView7.setMode(TriangleView.TYPE_LEFT_BOTTOM); TriangleView mClassifyView8 = (TriangleView) findViewById(R.id.classify_8); mClassifyView8.setMode(TriangleView.TYPE_RIGHT_TOP); } @Override  protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); } @Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); w = w - getPaddingRight() - getPaddingLeft(); float scale = w/660f; QiQiaoLayout.LayoutParams params = new QiQiaoLayout.LayoutParams((int)(230*scale),(int)(230*scale)); params.setMargins(0,0,(int)(10*scale),(int)(10*scale)); getChildAt(0).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(230*scale),(int)(230*scale)); params.setMargins((int)(10*scale),(int)(10*scale),0,0); getChildAt(1).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(120*scale),(int)(240*scale)); params.setMargins((int)(253*scale),0,0,0); getChildAt(2).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(250*scale),(int)(110*scale)); params.setMargins((int)(270*scale),0,0,(int)(10*scale)); getChildAt(3).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(120*scale),(int)(120*scale)); params.setMargins((int)(270*scale),(int)(120*scale),0,0); getChildAt(4).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(120*scale),(int)(120*scale)); params.setMargins((int)(400*scale),(int)(120*scale),0,0); getChildAt(5).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(120*scale),(int)(120*scale)); params.setMargins((int)(530*scale),(int)(120*scale),0,0); getChildAt(6).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(230*scale),(int)(230*scale)); params.setMargins((int)(430*scale),0,0,0); getChildAt(7).setLayoutParams(params); }
 
 
话不多说,看整个项目的代码更容易明白,项目地址是
https://pan.baidu.com/s/1bFvakI

 

 
 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闽农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值