class
/**
* Created by Venn on 2016/3/25.
*/
public class ShadowView extends View {
private static final int RECT = 100;//shape rectangular
private static final int CIRCLE = 101;//shape circle
private static final int ARC = 110;//shape arc
private Context mContext;
private Paint mPaint;
private int mShape;//shape what you want to draw
private int mColor;//the color of the shape
private boolean isStroke;//whether the shape is stroke
private int border;//the width of the border
private float radiusX, radiusY;//the radius of the shape(only use in rectangular)
private float startAngle, endAngle;//the angle of the shape(only use in arc)
private int gradientInterval;//the gradient interval of the color
public ShadowView(Context context) {
this(context, null);
}
public ShadowView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
TypedArray attributes = mContext.obtainStyledAttributes(attrs, R.styleable.ShadowView);
//get enum by getInt(int index,int defaultValue)
mShape = attributes.getInt(R.styleable.ShadowView_shadow_shape, RECT);
mColor = attributes.getColor(R.styleable.ShadowView_shadow_color, Color.GREEN);
isStroke = attributes.getBoolean(R.styleable.ShadowView_shadow_border_stroke, false);
border = attributes.getInteger(R.styleable.ShadowView_shadow_border, 5);
radiusX = attributes.getFloat(R.styleable.ShadowView_shadow_radius_x, 5.0f);
radiusY = attributes.getFloat(R.styleable.ShadowView_shadow_radius_y, 5.0f);
startAngle = attributes.getFloat(R.styleable.ShadowView_shadow_start_angle, 0);
endAngle = attributes.getFloat(R.styleable.ShadowView_shadow_end_angle, 90);
gradientInterval = attributes.getInteger(R.styleable.ShadowView_shadow_gradient_interval,
2);
attributes.recycle();
init();
}
private void init() {
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setStyle(isStroke ? Paint.Style.STROKE : Paint.Style.FILL);
mPaint.setStrokeWidth(border);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//handle wrap_content, if not handle, wrap_content will equals match_parent
int defaultDimension = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200,
mContext.getResources().getDisplayMetrics());
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
//according to the specMode calculate the display size
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(defaultDimension, defaultDimension);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(defaultDimension, heightSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize, defaultDimension);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//handle the padding, if not handle, the attribute won't effect
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
//calculate the real size
int left = paddingLeft;
int right = getWidth() - paddingRight;
int top = paddingTop;
int bottom = getHeight() - paddingBottom;
int len = Math.min(right - left, bottom - top) / gradientInterval;
int space = 0;
int drawColor = mColor;
//TODO can't parse color(need survey)
int alpha = mColor & Color.BLACK;
int red = mColor & Color.RED;
int green = mColor & Color.GREEN;
int blue = mColor & Color.BLUE;
switch (mShape) {
case RECT:
for (int i = 0; i < len; i++) {
space = i * gradientInterval;
//drawColor = Color.argb(alpha - space, red - space, green - space, blue -
// space);
mPaint.setColor(drawColor);
RectF rect = new RectF(left + space, top + space, right - space, bottom -
space);
canvas.drawRoundRect(rect, radiusX, radiusY, mPaint);
mPaint.setColor(Color.YELLOW);
space += gradientInterval;
RectF rectS = new RectF(left + space, top + space, right - space, bottom -
space);
canvas.drawRoundRect(rectS, radiusX, radiusY, mPaint);
}
break;
case CIRCLE:
for (int i = 0; i < len; i++) {
space = i * gradientInterval;
mPaint.setColor(drawColor);
int width = right - left;
int height = bottom - top;
int xPoint = width / 2 + paddingLeft;
int yPoint = height / 2 + paddingTop;
canvas.drawCircle(xPoint, yPoint, Math.min(width, height) / 2 - space, mPaint);
mPaint.setColor(Color.BLUE);
space += gradientInterval;
canvas.drawCircle(xPoint, yPoint, Math.min(width, height) / 2 - space, mPaint);
}
break;
case ARC:
for (int i = 0; i < len; i++) {
space = i * gradientInterval;
mPaint.setColor(drawColor);
RectF aRect = new RectF(left, top, right, bottom);
canvas.drawArc(aRect, startAngle, endAngle, isStroke, mPaint);
mPaint.setColor(Color.RED);
space += gradientInterval;
RectF rectS = new RectF(left + space, top + space, right - space, bottom -
space);
canvas.drawArc(rectS, startAngle, endAngle, isStroke, mPaint);
}
break;
}
}
// handle Touch event
@Override
public boolean onTouchEvent(MotionEvent event) {
//get VelocityTracker(速度追踪器) what is used to get the slide speed
VelocityTracker tracker = VelocityTracker.obtain();
tracker.addMovement(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// get touchSlop(触摸溢出):the min distance that a touch should slid,
// if the distance less than the touchSlop, think that's not a slide
ViewConfiguration configuration = ViewConfiguration.get(mContext);
int touchSlop = configuration.getScaledTouchSlop();
Log.i("touchSlop", "touchSlop:" + touchSlop);
break;
case MotionEvent.ACTION_MOVE:
//calculate the speed in 1000ms(distance in 1000ms/1000ms)
tracker.computeCurrentVelocity(1000);
float xVelocity = tracker.getXVelocity();
float yVelocity = tracker.getYVelocity();
Log.i("velocity", "xVelocity:" + xVelocity + ",yVelocity:" + yVelocity);
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
//clear and recycle the VelocityTracker
tracker.clear();
tracker.recycle();
return true;
}
private int getRandomColor() {
Random random = new Random(255);
int alpha = random.nextInt();
int red = random.nextInt();
int green = random.nextInt();
int blue = random.nextInt();
return Color.argb(alpha, red, green, blue);
}
}
格式
<declare-styleable name="ShadowView">
<attr name="shadow_color" format="color"/>
<attr name="shadow_border_stroke" format="boolean"/>
<attr name="shadow_border" format="integer"/>
<attr name="shadow_shape">
<enum name="RECT" value="100"/>
<enum name="CIRCLE" value="101"/>
<enum name="ARC" value="110"/>
attr>
<attr name="shadow_radius_x" format="float"/>
<attr name="shadow_radius_y" format="float"/>
<attr name="shadow_start_angle" format="float"/>
<attr name="shadow_end_angle" format="float"/>
<attr name="shadow_gradient_interval" format="integer"/>
declare-styleable>
布局
xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
>
<com.example.venn.costumeview.ui.customer.ShadowView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_light"
android:padding="20dp"
app:shadow_border="3"
app:shadow_border_stroke="true"
app:shadow_color="@android:color/holo_red_light"
app:shadow_end_angle="180"
app:shadow_gradient_interval="20"
app:shadow_radius_x="10.0"
app:shadow_radius_y="10.0"
app:shadow_shape="CIRCLE"
app:shadow_start_angle="30"
/>
LinearLayout>