弧形背景ShapeDrawable,PathShape,Path自定义图形边界

最近项目中用到这种效果,UX 圣诞度假,只能自力更生,开一波车了,记录下爬坑过程

先来个效果图

效果图

中间用到这个函数

public void quadTo(float x1, float y1, float x2, float y2){
	...
}

啦啦啦
这个参数x1,y1,是贝塞尔曲线的控制点,也就是起始位置的切线交点,弧形并没有经过它,这里我们需要三点确定圆弧,这里的贝塞尔曲线为二阶,为抛物线 f(x) = a * x * x+b * x+c,已知经过三点A(0,0),B(0,AB),C(AB/2,mArcImageViewTopHeight),可以求出函数表达式,再求其一阶导函数,带入A,B 点,得到AD BD 一次函数的斜率,分别带入A,B点,求出其切线方程,然后取得交点,一番折腾终于见到答案了,为 2 * mArcImageViewTopHeight
既然是二倍,那用几何推理证明下,如何证明?
还是回到正题吧,这是利用贝塞尔曲线画圆弧,当然这里面还需要证明 二阶贝塞尔曲线 为抛物线,这样推理就严密了,闲了再补充吧,

还有一种是画真正的圆弧,而不是贝塞尔曲线,那么我们需要计算圆弧所在圆的外接正方形的四点坐标,不过感觉这两个画出来的效果 差不多吧,看需求实现吧

在这里插入图片描述

CD,AC 为我们已知的高度

不妨 设 OA = OD = R ,AC = d  CD = h 
三角形OCA 勾股定理 得方程 
R * R - (R - d)  * (R - d) =  h * h
R = (d * d + h * h) / (2 * h)
此时,圆的外接正方形四个点 就有了 可以愉快的画真正的圆弧了

这里用的渐变色,如果是背景图片 需要用到BitmapShader

至于用到的android api 网上介绍很多就不展开了 这里用的是贝塞尔曲线实现的圆弧

全部代码

package com.example.zhangyan.myapplication;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Path;
import android.graphics.Shader;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.PathShape;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import com.zhang.test.R;

public class ArcBackgroundView extends View {

    private int mWidth;
    private int mHeight;
    private int mArcImageViewTopHeight;
    private Path mPath;
    private PathShape mPathShape;
    private int mArcBackgroundViewEndColor;
    private int mArcBackgroundViewStartColor;
    private int[] mColors;
    private LinearGradient mLinearGradient;
    private ShapeDrawable mShapeDrawable;

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

    public ArcBackgroundView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ArcBackgroundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

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

    private void init(AttributeSet attrs, Context context) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ArcBackgroundView);
        mArcBackgroundViewEndColor = typedArray.getColor(R.styleable.ArcBackgroundView_ArcBackgroundViewEndColor, mArcBackgroundViewEndColor);
        mArcBackgroundViewStartColor = typedArray.getColor(R.styleable.ArcBackgroundView_ArcBackgroundViewStartColor, mArcBackgroundViewStartColor);
        mArcImageViewTopHeight = typedArray.getDimensionPixelOffset(R.styleable.ArcBackgroundView_ArcBackgroundViewTopHeight, 0);
        mPath = new Path();
        typedArray.recycle();
        mColors = new int[]{mArcBackgroundViewStartColor, mArcBackgroundViewEndColor};
        mShapeDrawable = new ShapeDrawable();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPath.reset();
        mPath.moveTo(0, 0);
        mPath.quadTo(mWidth/2, mArcImageViewTopHeight * 2,mWidth, 0);
        mPath.lineTo(mWidth,mHeight);
        mPath.lineTo(0,mHeight);
        mPath.close();
        if (mPathShape == null) {
            mPathShape = new PathShape(mPath, mWidth,mHeight);
            mLinearGradient = new LinearGradient(0, 0, 0, mHeight, mColors, null, Shader.TileMode.CLAMP);
        }
        mShapeDrawable.setShape(mPathShape);
        mShapeDrawable.setBounds(0,0,mWidth,mHeight);
        mShapeDrawable.getPaint().setShader(mLinearGradient);
        mShapeDrawable.draw(canvas);
    }
}
自定义属性
<declare-styleable name="ArcBackgroundView">
    <attr name="ArcBackgroundViewStartColor" format="color" />
    <attr name="ArcBackgroundViewTopHeight" format="dimension" />
    <attr name="ArcBackgroundViewEndColor" format="color" />
</declare-styleable>
使用
 <com.example.zhangyan.myapplication.ArcBackgroundView
        android:layout_width="match_parent"
        android:layout_marginTop="90dp"
        app:ArcBackgroundViewEndColor="#f0f"
        app:ArcBackgroundViewStartColor="#ff0"
        app:ArcBackgroundViewTopHeight="80dp"
        android:layout_height="400dp" />
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值