自定义view 圆角相对布局

跟以前一样还是先上效果图图片如下
相对布局

相信不少童鞋都在为定义圆角图片而苦恼,这里我们提供了一个圆角相对布局比起圆角图片复用性更好,能嵌套任何想变成圆角的内容,处理也是相当简单的下面来看代码处理。

/**
 * 作用:圆角相对布局
 * 作者:KangJH
 */
public class RCRelativeLayout extends RelativeLayout {
    public float[] radii = {0, 0, 0, 0, 0, 0, 0, 0};  // top-left, top-right, bottom-right, bottom-left
    public Path mClipPath;                            // 剪裁区域路径
    public Paint mPaint;                              // 画笔
    public int mEdgeFix = 10;                        // 边缘修复
    public RectF mLayer;                             // 画布图层大小

    public RCRelativeLayout(Context context) {
        this(context, null);
    }

    public RCRelativeLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RCRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mLayer = new RectF();
        mClipPath = new Path();
        mPaint = new Paint();
        mPaint.setColor(Color.WHITE);
        mPaint.setAntiAlias(true);
    }

    @Override//当调用invalidate的时候会首先调用该处理
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mLayer.set(0, 0, w, h);
        refreshRegion();
    }

    @Override//系统方法替代viewgroup的draw
    protected void dispatchDraw(Canvas canvas) {
        canvas.saveLayer(mLayer, null, Canvas.ALL_SAVE_FLAG);
        super.dispatchDraw(canvas);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawPath(mClipPath, mPaint);
        canvas.restore();
    }

    @Override//在设置背景的情况下会调用draw方法 或者设置willnotdraw为false会调用因此要添加切割背景的处理
    public void draw(Canvas canvas) {
        refreshRegion();
        canvas.save();
        canvas.clipPath(mClipPath);
        super.draw(canvas);
        canvas.restore();
    }

    public void refreshRegion() {
        int w = (int) mLayer.width();
        int h = (int) mLayer.height();
        mClipPath.reset();
        mClipPath.addRoundRect(new RectF(getPaddingLeft(), getPaddingTop(), w - getPaddingRight(), h - getPaddingBottom()), radii, Path.Direction.CW);
        mClipPath.moveTo(-mEdgeFix, -mEdgeFix);  // 通过空操作让Path区域占满画布
        mClipPath.moveTo(w + mEdgeFix, h + mEdgeFix);
    }

    public void setRadius(int radius) {
        for (int i = 0; i < radii.length; i++) {
            radii[i] = radius;
        }
        invalidate();
    }
}

对外调用的处理就一个setRadius当然大家如果想添加其他处理可以向外添加方法这里我只讲最简单最核心的处理。
构造方法里面的初始化就不做过多介绍了,大家应该都明白。
当调用invalidate方法是我们首先调用的是onSizeChanged方法,refreshRegion处理是通过path划出圆角矩形的轮廓,mClipPath.moveTo的处理很关键没有这两行zailistview快速滑动过程中可能会导致有些圆角首先展示直角然后逐渐变为圆角。
如果没有设置背景之后会调用dispatchDraw处理将path画到画布上,如果有背景会调用draw这里的处理是将背景切割保证背景也是圆角的。
下面就是外部的调用,也是十分简单代码如下

public class MainActivity extends AppCompatActivity {
    private ListView lv_main;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lv_main = findViewById(R.id.lv_main);
        List<String> aas = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            aas.add("sss");
        }
        lv_main.setAdapter(new MyAdapter(aas));

    }

    class MyAdapter extends BaseAdapter {
        private List<String> datas;

        public MyAdapter(List<String> datas) {
            this.datas = datas;
        }

        @Override
        public int getCount() {
            return datas.size();
        }

        @Override
        public Object getItem(int position) {
            return datas.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            @SuppressLint("ViewHolder") View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_rount_rect, null);
            RCRelativeLayout rc_rl = view.findViewById(R.id.rc_rl);
            rc_rl.setRadius(30);
            return view;
        }
    }
}

下面是item的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.example.pc_304.testrrelativelayout.RCRelativeLayout
        android:id="@+id/rc_rl"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        android:background="#ffffff">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/download"
            android:contentDescription="@string/app_name" />
    </com.example.pc_304.testrrelativelayout.RCRelativeLayout>

</RelativeLayout>

主界面布局如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.example.pc_304.testrrelativelayout.MainActivity">

    <ListView
        android:id="@+id/lv_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

怎么样是不是很简单。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值