diff --git a/app/src/main/java/com/bonait/bnframework/common/DashboardView.java b/app/src/main/java/com/bonait/bnframework/common/DashboardView.java new file mode 100644 index 00000000..c220dc07 --- /dev/null +++ b/app/src/main/java/com/bonait/bnframework/common/DashboardView.java @@ -0,0 +1,492 @@ +package com.bonait.bnframework.common; + + + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.SweepGradient; +//import android.support.v4.content.ContextCompat; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.View; +import android.view.animation.LinearInterpolator; + +import com.bonait.bnframework.business.ExecuteTheRecipe; + +import java.util.Random; + + +/** + * DashboardView style 4,仿汽车速度仪表盘 + * Created by woxingxiao on 2016-12-19. + */ +public class DashboardView extends View { + + private int mRadius; // 扇形半径 + private int mStartAngle = 150; // 起始角度 + private int mSweepAngle = 240; // 绘制角度 + private int mMin = 0; // 最小值 + private int mMax = 180; // 最大值 + private int mSection = 10; // 值域(mMax-mMin)等分份数 + private int mPortion = 5; // 一个mSection等分份数 + private String mHeaderText = "km/h"; // 表头 + private float mVelocity = mMin; // 实时速度 + private int mStrokeWidth; // 画笔宽度 + private int mLength1; // 长刻度的相对圆弧的长度 + private int mLength2; // 刻度读数顶部的相对圆弧的长度 + private int mPLRadius; // 指针长半径 + private int mPSRadius; // 指针短半径 + + private int mPadding; + private float mCenterX, mCenterY; // 圆心坐标 + private Paint mPaint; + private Path pointerPath=new Path(); + private Paint pointerPaint=new Paint(); + private boolean IsInit=false; + private RectF mRectFArc; + private RectF mRectFInnerArc; + private Rect mRectText; + private String[] mTexts; + private int[] mColors; + private Paint mTextPaint=new Paint(); + private int textSize=40; + + private String unity="℃"; + private int textColor=Color.parseColor("#03A9F4"); + private int backgroundColor=Color.parseColor("#292a30"); + + public void setMaxValue(int maxValue){ + mMax=maxValue; + init(); + } + + public void setHeaderText(String header){ + mHeaderText=header; + init(); + } + + public void setBackgroundColor(int color){ + backgroundColor=color; + } + + public void setTextSize(int size){ + textSize=size; + } + + public void setTextColor(int color){ + textColor=color; + } + + public void setUnity(String mUnity){ + unity=mUnity; + } + + public DashboardView(Context context) { + this(context, null); + } + + public DashboardView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DashboardView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + init(); + } + + private void init() { + mStrokeWidth = dp2px(3); + mLength1 = dp2px(8) + mStrokeWidth; + mLength2 = mLength1 + dp2px(4); + + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setStrokeCap(Paint.Cap.ROUND); + + mRectFArc = new RectF(); + mRectFInnerArc = new RectF(); + mRectText = new Rect(); + + mTexts = new String[mSection + 1]; // 需要显示mSection + 1个刻度读数 + for (int i = 0; i < mTexts.length; i++) { + int n = (mMax - mMin) / mSection; + mTexts[i] = String.valueOf(mMin + i * n); + } + mColors = new int[]{Color.GREEN, Color.YELLOW, Color.RED};//内圆渐变设置 + } + + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + mPadding = Math.max( + Math.max(getPaddingLeft(), getPaddingTop()), + Math.max(getPaddingRight(), getPaddingBottom()) + ); + setPadding(mPadding, mPadding, mPadding, mPadding); + + int width = resolveSize(dp2px(260), widthMeasureSpec); + mRadius = (width - mPadding * 2 - mStrokeWidth * 2) / 2; + + // 由起始角度确定的高度 + float[] point1 = getCoordinatePoint(mRadius, mStartAngle); + // 由结束角度确定的高度 + float[] point2 = getCoordinatePoint(mRadius, mStartAngle + mSweepAngle); + int height = (int) Math.max(point1[1] + mRadius + mStrokeWidth * 2, + point2[1] + mRadius + mStrokeWidth * 2); + setMeasuredDimension(width, height + getPaddingTop() + getPaddingBottom()); + + mCenterX = mCenterY = getMeasuredWidth() / 2f; + mRectFArc.set( + getPaddingLeft() + mStrokeWidth, + getPaddingTop() + mStrokeWidth, + getMeasuredWidth() - getPaddingRight() - mStrokeWidth, + getMeasuredWidth() - getPaddingBottom() - mStrokeWidth + ); + + mPaint.setTextSize(sp2px(16)); + mPaint.getTextBounds("0", 0, "0".length(), mRectText); + mRectFInnerArc.set( + getPaddingLeft() + mLength2 + mRectText.height() + dp2px(30), + getPaddingTop() + mLength2 + mRectText.height() + dp2px(30), + getMeasuredWidth() - getPaddingRight() - mLength2 - mRectText.height() - dp2px(30), + getMeasuredWidth() - getPaddingBottom() - mLength2 - mRectText.height() - dp2px(30) + ); + + mPLRadius = mRadius - dp2px(10); + mPSRadius = dp2px(25); + } + + private float Scale(float InputValue, float InputMax, float InputMin, float OutMax, float OutMin) + { + float value = ((OutMax - OutMin) * (InputValue - InputMin)) / (InputMax - InputMin) + OutMin; + if (value > OutMax) return OutMax; + if (value < OutMin) return OutMin; + return value; + } + + private void CanvasInit(Canvas canvas){ + mPaint.reset(); + pointerPaint.reset(); + pointerPath.reset(); + mTextPaint.reset(); + + canvas.drawColor(backgroundColor);//背景色 + this.setPadding(10,30,10,10); + + /** + * 画圆弧 + */ + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(mStrokeWidth); + mPaint.setColor(Color.parseColor("#03A9F4")); + canvas.drawArc(mRectFArc, mStartAngle, mSweepAngle, false, mPaint); + + /** + * 画长刻度 + * 画好起始角度的一条刻度后通过canvas绕着原点旋转来画剩下的长刻度 + */ + double cos = Math.cos(Math.toRadians(mStartAngle - 180)); + double sin = Math.sin(Math.toRadians(mStartAngle - 180)); + float x0 = (float) (mPadding + mStrokeWidth + mRadius * (1 - cos)); + float y0 = (float) (mPadding + mStrokeWidth + mRadius * (1 - sin)); + float x1 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1) * cos); + float y1 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - mLength1) * sin); + + canvas.save(); + canvas.drawLine(x0, y0, x1, y1, mPaint); + float angle = mSweepAngle * 1f / mSection; + for (int i = 0; i < mSection; i++) { + canvas.rotate(angle, mCenterX, mCenterY); + canvas.drawLine(x0, y0, x1, y1, mPaint); + } + canvas.restore(); + + /** + * 画短刻度 + * 同样采用canvas的旋转原理 + */ + canvas.save(); + mPaint.setStrokeWidth(mStrokeWidth / 2f); + float x2 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - 2 * mLength1 / 3f) * cos); + float y2 = (float) (mPadding + mStrokeWidth + mRadius - (mRadius - 2 * mLength1 / 3f) * sin); + canvas.drawLine(x0, y0, x2, y2, mPaint); + angle = mSweepAngle * 1f / (mSection * mPortion); + for (int i = 1; i < mSection * mPortion; i++) { + canvas.rotate(angle, mCenterX, mCenterY); + if (i % mPortion == 0) { // 避免与长刻度画重合 + continue; + } + canvas.drawLine(x0, y0, x2, y2, mPaint); + } + canvas.restore(); + + /** + * 画长刻度读数 + */ + mPaint.setTextSize(sp2px(16)); + mPaint.setStyle(Paint.Style.FILL); + float α; + float[] p; + angle = mSweepAngle * 1f / mSection; + for (int i = 0; i <= mSection; i++) { + α = mStartAngle + angle * i; + p = getCoordinatePoint(mRadius - mLength2, α); + if (α % 360 > 135 && α % 360 < 225) { + mPaint.setTextAlign(Paint.Align.LEFT); + } else if ((α % 360 >= 0 && α % 360 < 45) || (α % 360 > 315 && α % 360 <= 360)) { + mPaint.setTextAlign(Paint.Align.RIGHT); + } else { + mPaint.setTextAlign(Paint.Align.CENTER); + } + try { + mPaint.getTextBounds(mHeaderText, 0, mTexts[i].length(), mRectText); + }catch(Exception e){} + + int txtH = mRectText.height(); + if (i <= 1 || i >= mSection - 1) { + canvas.drawText(mTexts[i], p[0], p[1] + txtH / 2, mPaint); + } else if (i == 3) { + canvas.drawText(mTexts[i], p[0] + txtH / 2, p[1] + txtH, mPaint); + } else if (i == mSection - 3) { + canvas.drawText(mTexts[i], p[0] - txtH / 2, p[1] + txtH, mPaint); + } else { + canvas.drawText(mTexts[i], p[0], p[1] + txtH, mPaint); + } + } + + mPaint.setStrokeCap(Paint.Cap.SQUARE); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setStrokeWidth(dp2px(10)); + mPaint.setShader(generateSweepGradient()); + canvas.drawArc(mRectFInnerArc, mStartAngle + 1, mSweepAngle - 2, false, mPaint); + + mPaint.setStrokeCap(Paint.Cap.ROUND); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setShader(null); + + /** + * 画表头 + * 没有表头就不画 + */ + if (!TextUtils.isEmpty(mHeaderText)) { + mPaint.setTextSize(textSize); + mPaint.setColor(textColor); + mPaint.setTextAlign(Paint.Align.CENTER); + mPaint.getTextBounds(mHeaderText, 0, mHeaderText.length(), mRectText); + canvas.drawText(mHeaderText, mCenterX, mCenterY + dp2px(100), mPaint); +// canvas.drawText(mHeaderText, mCenterX, mCenterY - mRectText.height() * 3, mPaint); + } + + /** + * 画指针 + */ + float θ = mStartAngle + mSweepAngle * (mVelocity - mMin) / (mMax - mMin); // 指针与水平线夹角 + int r = mRadius / 8; + int tempWidth = 10; + canvas.save(); + canvas.translate(getMeasuredWidth() / 2, mCenterY); + canvas.rotate(θ); + pointerPaint.setColor(Color.parseColor("#03A9F4")); + pointerPaint.setAntiAlias(true);//抗锯齿 + pointerPath.moveTo(mRadius-this.getPaddingLeft()-30, 0); + pointerPath.lineTo(0, 0 - tempWidth); + pointerPath.lineTo(0, 0 + tempWidth); + pointerPath.close(); + canvas.drawPath(pointerPath, pointerPaint); + canvas.restore(); + + /** + * 中心圆 + */ + mPaint.setColor(Color.parseColor("#CCCCCC")); + canvas.drawCircle(mCenterX, mCenterY, r, mPaint); + + /** + * 画实时度数值 + */ + mPaint.setColor(Color.parseColor("#6200EE")); + mPaint.setStrokeWidth(dp2px(2)); + int xOffset = dp2px(22); + + mTextPaint.reset(); + mTextPaint.setColor(Color.WHITE); + mTextPaint.setTextAlign(Paint.Align.CENTER); + mTextPaint.setTextSize(textSize); + mTextPaint.setColor(textColor); + mTextPaint.setAntiAlias(true); + canvas.drawText( String.format("%.2f", mVelocity)+unity,mCenterX, mCenterY + dp2px(60),mTextPaint); + + } + + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + CanvasInit(canvas); + } + + /** + * 数码管样式 + */ + // 1 + // —— + // 2 | | 3 + // —— 4 + // 5 | | 6 + // —— + // 7 + private void drawDigitalTube(Canvas canvas, float num, int xOffset) { + float x = mCenterX + xOffset; + float y = mCenterY + dp2px(40); + int lx = dp2px(5); + int ly = dp2px(10); + int gap = dp2px(2); + + // 1 + mPaint.setAlpha(num == -1 || num == 1 || num == 4 ? 25 : 255); + canvas.drawLine(x - lx, y, x + lx, y, mPaint); + // 2 + mPaint.setAlpha(num == -1 || num == 1 || num == 2 || num == 3 || num == 7 ? 25 : 255); + canvas.drawLine(x - lx - gap, y + gap, x - lx - gap, y + gap + ly, mPaint); + // 3 + mPaint.setAlpha(num == -1 || num == 5 || num == 6 ? 25 : 255); + canvas.drawLine(x + lx + gap, y + gap, x + lx + gap, y + gap + ly, mPaint); + // 4 + mPaint.setAlpha(num == -1 || num == 0 || num == 1 || num == 7 ? 25 : 255); + canvas.drawLine(x - lx, y + gap * 2 + ly, x + lx, y + gap * 2 + ly, mPaint); + // 5 + mPaint.setAlpha(num == -1 || num == 1 || num == 3 || num == 4 || num == 5 || num == 7 + || num == 9 ? 25 : 255); + canvas.drawLine(x - lx - gap, y + gap * 3 + ly, + x - lx - gap, y + gap * 3 + ly * 2, mPaint); + // 6 + mPaint.setAlpha(num == -1 || num == 2 ? 25 : 255); + canvas.drawLine(x + lx + gap, y + gap * 3 + ly, + x + lx + gap, y + gap * 3 + ly * 2, mPaint); + // 7 + mPaint.setAlpha(num == -1 || num == 1 || num == 4 || num == 7 ? 25 : 255); + canvas.drawLine(x - lx, y + gap * 4 + ly * 2, x + lx, y + gap * 4 + ly * 2, mPaint); + } + + private int dp2px(int dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, + Resources.getSystem().getDisplayMetrics()); + } + + private int sp2px(int sp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, + Resources.getSystem().getDisplayMetrics()); + } + + public float[] getCoordinatePoint(int radius, float angle) { + float[] point = new float[2]; + + double arcAngle = Math.toRadians(angle); //将角度转换为弧度 + if (angle < 90) { + point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius); + point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius); + } else if (angle == 90) { + point[0] = mCenterX; + point[1] = mCenterY + radius; + } else if (angle > 90 && angle < 180) { + arcAngle = Math.PI * (180 - angle) / 180.0; + point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius); + point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius); + } else if (angle == 180) { + point[0] = mCenterX - radius; + point[1] = mCenterY; + } else if (angle > 180 && angle < 270) { + arcAngle = Math.PI * (angle - 180) / 180.0; + point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius); + point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius); + } else if (angle == 270) { + point[0] = mCenterX; + point[1] = mCenterY - radius; + } else { + arcAngle = Math.PI * (360 - angle) / 180.0; + point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius); + point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius); + } + + return point; + } + + private SweepGradient generateSweepGradient() { + SweepGradient sweepGradient = new SweepGradient(mCenterX, mCenterY, + mColors, + new float[]{0, 140 / 360f, mSweepAngle / 360f} + ); + + Matrix matrix = new Matrix(); + matrix.setRotate(mStartAngle - 3, mCenterX, mCenterY); + sweepGradient.setLocalMatrix(matrix); + + return sweepGradient; + } + + public float getVelocity() { + return mVelocity; + } + + public void setVelocity(float velocity) { + if (mVelocity == velocity || velocity < mMin || velocity > mMax) { + return; + } + mVelocity = velocity; + postInvalidate(); + } + + + private boolean isAnimFinished = true; + + public void setValue(float value){ + if (isAnimFinished) { + ObjectAnimator animator = ObjectAnimator.ofFloat(this, "setVelocity", getVelocity(), value); + animator.setDuration(100).setInterpolator(new LinearInterpolator()); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + isAnimFinished = false; + } + + @Override + public void onAnimationEnd(Animator animation) { + isAnimFinished = true; + } + + @Override + public void onAnimationCancel(Animator animation) { + isAnimFinished = true; + } + }); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float value = (float)animation.getAnimatedValue(); + setVelocity(value); + } + }); + animator.start(); + } + + } + +} + diff --git a/app/src/main/java/com/bonait/bnframework/common/ShadowContainer.java b/app/src/main/java/com/bonait/bnframework/common/ShadowContainer.java new file mode 100644 index 00000000..5927b76c --- /dev/null +++ b/app/src/main/java/com/bonait/bnframework/common/ShadowContainer.java @@ -0,0 +1,214 @@ +package com.bonait.bnframework.common; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; +import android.os.Build; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +import com.bonait.bnframework.R; + + +/** + * 阴影容器 + * 需要在 res->values->attrs.xml中添加以下内容 + * + * + * + * + * + * + * + * + * + * Reference: https://github.com/cjlemon/Shadow + */ +public class ShadowContainer extends ViewGroup { + + private final float deltaLength; + private final float cornerRadius; + private final Paint mShadowPaint; + private boolean drawShadow; + + public ShadowContainer(Context context) { + this(context, null); + } + + public ShadowContainer(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ShadowContainer(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShadowContainer); + int shadowColor = a.getColor(R.styleable.ShadowContainer_containerShadowColor, Color.RED); + float shadowRadius = a.getDimension(R.styleable.ShadowContainer_containerShadowRadius, 0); + deltaLength = a.getDimension(R.styleable.ShadowContainer_containerDeltaLength, 0); + cornerRadius = a.getDimension(R.styleable.ShadowContainer_containerCornerRadius, 0); + float dx = a.getDimension(R.styleable.ShadowContainer_deltaX, 0); + float dy = a.getDimension(R.styleable.ShadowContainer_deltaY, 0); + drawShadow = a.getBoolean(R.styleable.ShadowContainer_enable, true); + a.recycle(); + mShadowPaint = new Paint(); + mShadowPaint.setStyle(Paint.Style.FILL); + mShadowPaint.setAntiAlias(true); + mShadowPaint.setColor(shadowColor); + mShadowPaint.setShadowLayer(shadowRadius, dx, dy, shadowColor); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (drawShadow) { + /* + setShadowLayer()/setMaskFilter is not support hardware acceleration, so using LAYER_TYPE_SOFTWARE, but software layers isn't always good. + LAYER_TYPE_SOFTWARE: software layers should be avoided when the affected view tree updates often. + */ + if (getLayerType() != LAYER_TYPE_SOFTWARE) { + setLayerType(LAYER_TYPE_SOFTWARE, null); + } + View child = getChildAt(0); + int left = child.getLeft(); + int top = child.getTop(); + int right = child.getRight(); + int bottom = child.getBottom(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius, mShadowPaint); + } else { + Path drawablePath = new Path(); + drawablePath.moveTo(left + cornerRadius, top); + drawablePath.arcTo(new RectF(left, top, left + 2 * cornerRadius, top + 2 * cornerRadius), -90, -90, false); + drawablePath.lineTo(left, bottom - cornerRadius); + drawablePath.arcTo(new RectF(left, bottom - 2 * cornerRadius, left + 2 * cornerRadius, bottom), 180, -90, false); + drawablePath.lineTo(right - cornerRadius, bottom); + drawablePath.arcTo(new RectF(right - 2 * cornerRadius, bottom - 2 * cornerRadius, right, bottom), 90, -90, false); + drawablePath.lineTo(right, top + cornerRadius); + drawablePath.arcTo(new RectF(right - 2 * cornerRadius, top, right, top + 2 * cornerRadius), 0, -90, false); + drawablePath.close(); + canvas.drawPath(drawablePath, mShadowPaint); + } + } + super.dispatchDraw(canvas); + } + + /** + * setMeasuredDimension(): store the modified width and modified height. + * + * @param widthMeasureSpec the original width + * @param heightMeasureSpec the original height + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (getChildCount() != 1) { + throw new IllegalStateException("Child View can have only one!!!"); + } + int measuredWidth = getMeasuredWidth(); + int measuredHeight = getMeasuredHeight(); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + View child = getChildAt(0); + MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams(); + int childBottomMargin = (int) (Math.max(deltaLength, layoutParams.bottomMargin) + 1); + int childLeftMargin = (int) (Math.max(deltaLength, layoutParams.leftMargin) + 1); + int childRightMargin = (int) (Math.max(deltaLength, layoutParams.rightMargin) + 1); + int childTopMargin = (int) (Math.max(deltaLength, layoutParams.topMargin) + 1); + int widthMeasureSpecMode; + int widthMeasureSpecSize; + int heightMeasureSpecMode; + int heightMeasureSpecSize; + if (widthMode == MeasureSpec.UNSPECIFIED) { + widthMeasureSpecMode = MeasureSpec.UNSPECIFIED; + widthMeasureSpecSize = MeasureSpec.getSize(widthMeasureSpec); + } else { + if (layoutParams.width == MarginLayoutParams.MATCH_PARENT) { + widthMeasureSpecMode = MeasureSpec.EXACTLY; + widthMeasureSpecSize = measuredWidth - childLeftMargin - childRightMargin; + } else if (MarginLayoutParams.WRAP_CONTENT == layoutParams.width) { + widthMeasureSpecMode = MeasureSpec.AT_MOST; + widthMeasureSpecSize = measuredWidth - childLeftMargin - childRightMargin; + } else { + widthMeasureSpecMode = MeasureSpec.EXACTLY; + widthMeasureSpecSize = layoutParams.width; + } + } + if (heightMode == MeasureSpec.UNSPECIFIED) { + heightMeasureSpecMode = MeasureSpec.UNSPECIFIED; + heightMeasureSpecSize = MeasureSpec.getSize(heightMeasureSpec); + } else { + if (layoutParams.height == MarginLayoutParams.MATCH_PARENT) { + heightMeasureSpecMode = MeasureSpec.EXACTLY; + heightMeasureSpecSize = measuredHeight - childBottomMargin - childTopMargin; + } else if (MarginLayoutParams.WRAP_CONTENT == layoutParams.height) { + heightMeasureSpecMode = MeasureSpec.AT_MOST; + heightMeasureSpecSize = measuredHeight - childBottomMargin - childTopMargin; + } else { + heightMeasureSpecMode = MeasureSpec.EXACTLY; + heightMeasureSpecSize = layoutParams.height; + } + } + measureChild(child, MeasureSpec.makeMeasureSpec(widthMeasureSpecSize, widthMeasureSpecMode), MeasureSpec.makeMeasureSpec(heightMeasureSpecSize, heightMeasureSpecMode)); + int parentWidthMeasureSpec = MeasureSpec.getMode(widthMeasureSpec); + int parentHeightMeasureSpec = MeasureSpec.getMode(heightMeasureSpec); + int height = measuredHeight; + int width = measuredWidth; + int childHeight = child.getMeasuredHeight(); + int childWidth = child.getMeasuredWidth(); + if (parentHeightMeasureSpec == MeasureSpec.AT_MOST) { + height = childHeight + childTopMargin + childBottomMargin; + } + if (parentWidthMeasureSpec == MeasureSpec.AT_MOST) { + width = childWidth + childRightMargin + childLeftMargin; + } + if (width < childWidth + 2 * deltaLength) { + width = (int) (childWidth + 2 * deltaLength); + } + if (height < childHeight + 2 * deltaLength) { + height = (int) (childHeight + 2 * deltaLength); + } + if (height != measuredHeight || width != measuredWidth) { + setMeasuredDimension(width, height); + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + View child = getChildAt(0); + int measuredWidth = getMeasuredWidth(); + int measuredHeight = getMeasuredHeight(); + int childMeasureWidth = child.getMeasuredWidth(); + int childMeasureHeight = child.getMeasuredHeight(); + child.layout((measuredWidth - childMeasureWidth) / 2, (measuredHeight - childMeasureHeight) / 2, (measuredWidth + childMeasureWidth) / 2, (measuredHeight + childMeasureHeight) / 2); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT); + } + + @Override + protected LayoutParams generateLayoutParams(LayoutParams p) { + return new MarginLayoutParams(p); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new MarginLayoutParams(getContext(), attrs); + } + + public void setDrawShadow(boolean drawShadow) { + if (this.drawShadow == drawShadow) { + return; + } + this.drawShadow = drawShadow; + postInvalidate(); + } + +} + + diff --git a/app/src/main/res/drawable/rectancle.xml b/app/src/main/res/drawable/rectancle.xml new file mode 100644 index 00000000..f738fb31 --- /dev/null +++ b/app/src/main/res/drawable/rectancle.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/datatab/layout/activity_main.xml b/app/src/main/res/layout/datatab/layout/activity_main.xml index 84d0aea9..7868ea51 100644 --- a/app/src/main/res/layout/datatab/layout/activity_main.xml +++ b/app/src/main/res/layout/datatab/layout/activity_main.xml @@ -19,6 +19,7 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file