最近项目中用到这种效果,UX 圣诞度假,只能自力更生,开一波车了,记录下爬坑过程
先来个效果图
中间用到这个函数
public void quadTo(float x1, float y1, float x2, float y2){
...
}
这个参数x1,y1,是贝塞尔曲线的控制点,也就是起始位置的切线交点,弧形并没有经过它,这里我们需要三点确定圆弧,也就是下图中的E,D,A,而E点就是我们view的左上顶点,A点是我们的右上顶点,CD的长度是我们自定义的高度ArcBackgroundViewTopHeight,用来控制圆弧,那我们需要知道B点相对于E点的坐标就可以画出来了,怎么算呢?
一度陷入了计算中,解出来感觉这是个初中证明题,添加个辅助线CF,C是AE的中点,△ACF 相似于△AEB,那么AC/AE = AF/AB=1/2,也就是F是AB的中点,同理△BDF 相似于△BEA ,那么BD/BC = BF/BA = 1/2,即D为BC的中点,那么控制点的相对于view 原点E的坐标就是 mArcBackgroundViewTopHeight * 2
这里用的渐变色,如果是背景图片 需要用到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" />