2019-11-20 19:15:56
代码来自github,忘记是谁写的了,底子不错,适当做了点修改
===================================================
ShadowContainer
1 package com.example.android_research; 2 3 import android.content.Context; 4 import android.content.res.TypedArray; 5 import android.graphics.Canvas; 6 import android.graphics.Color; 7 import android.graphics.Paint; 8 import android.graphics.Path; 9 import android.graphics.RectF; 10 import android.os.Build; 11 import android.util.AttributeSet; 12 import android.view.View; 13 import android.view.ViewGroup; 14 15 /** 16 * <p> 17 * Created by weiwei22 on 2019-11-20. 18 */ 19 public class ShadowContainer extends ViewGroup { 20 private final float topDeltaLength; 21 private final float bottomDeltaLength; 22 private final float leftDeltaLength; 23 private final float rightDeltaLength; 24 private final float cornerRadius; 25 private final Paint mShadowPaint; 26 private boolean drawShadow; 27 28 public ShadowContainer(Context context) { 29 this(context, null); 30 } 31 32 public ShadowContainer(Context context, AttributeSet attrs) { 33 this(context, attrs, 0); 34 } 35 36 public ShadowContainer(Context context, AttributeSet attrs, int defStyleAttr) { 37 super(context, attrs, defStyleAttr); 38 39 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ShadowContainer); 40 topDeltaLength = a.getDimension(R.styleable.ShadowContainer_topDeltaLength, 0); 41 bottomDeltaLength = a.getDimension(R.styleable.ShadowContainer_bottomDeltaLength, 0); 42 leftDeltaLength = a.getDimension(R.styleable.ShadowContainer_leftDeltaLength, 0); 43 rightDeltaLength = a.getDimension(R.styleable.ShadowContainer_rightDeltaLength, 0); 44 cornerRadius = a.getDimension(R.styleable.ShadowContainer_containerCornerRadius, 0); 45 drawShadow = a.getBoolean(R.styleable.ShadowContainer_enable, true); 46 float dx = a.getDimension(R.styleable.ShadowContainer_deltaX, 0); 47 float dy = a.getDimension(R.styleable.ShadowContainer_deltaY, 0); 48 float shadowRadius = a.getDimension(R.styleable.ShadowContainer_containerShadowRadius, 0); 49 int shadowColor = a.getColor(R.styleable.ShadowContainer_containerShadowColor, Color.RED); 50 a.recycle(); 51 52 mShadowPaint = new Paint(); 53 mShadowPaint.setStyle(Paint.Style.FILL); 54 mShadowPaint.setAntiAlias(true); 55 mShadowPaint.setColor(shadowColor); 56 mShadowPaint.setShadowLayer(shadowRadius, dx, dy, shadowColor); 57 } 58 59 @Override 60 protected void onFinishInflate() { 61 super.onFinishInflate(); 62 } 63 64 @Override 65 protected void dispatchDraw(Canvas canvas) { 66 if (drawShadow) { 67 if (getLayerType() != LAYER_TYPE_SOFTWARE) { 68 setLayerType(LAYER_TYPE_SOFTWARE, null); 69 } 70 View child = getChildAt(0); 71 int left = child.getLeft(); 72 int top = child.getTop(); 73 int right = child.getRight(); 74 int bottom = child.getBottom(); 75 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 76 canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius, mShadowPaint); 77 } else { 78 Path drawablePath = new Path(); 79 drawablePath.moveTo(left + cornerRadius, top); 80 drawablePath.arcTo(new RectF(left, top, left + 2 * cornerRadius, top + 2 * cornerRadius), -90, -90, false); 81 drawablePath.lineTo(left, bottom - cornerRadius); 82 drawablePath.arcTo(new RectF(left, bottom - 2 * cornerRadius, left + 2 * cornerRadius, bottom), 180, -90, false); 83 drawablePath.lineTo(right - cornerRadius, bottom); 84 drawablePath.arcTo(new RectF(right - 2 * cornerRadius, bottom - 2 * cornerRadius, right, bottom), 90, -90, false); 85 drawablePath.lineTo(right, top + cornerRadius); 86 drawablePath.arcTo(new RectF(right - 2 * cornerRadius, top, right, top + 2 * cornerRadius), 0, -90, false); 87 drawablePath.close(); 88 canvas.drawPath(drawablePath, mShadowPaint); 89 } 90 } 91 super.dispatchDraw(canvas); 92 } 93 94 public void setDrawShadow(boolean drawShadow) { 95 if (this.drawShadow == drawShadow) { 96 return; 97 } 98 this.drawShadow = drawShadow; 99 postInvalidate(); 100 } 101 102 @Override 103 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 104 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 105 if (getChildCount() != 1) { 106 throw new IllegalStateException("Child view must be ony one!"); 107 } 108 int measuredWidth = getMeasuredWidth(); 109 int measuredHeight = getMeasuredHeight(); 110 int widthMode = MeasureSpec.getMode(widthMeasureSpec); 111 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 112 View child = getChildAt(0); 113 ShadowLayoutParams layoutParams = (ShadowLayoutParams) child.getLayoutParams(); 114 int childBottomMargin = (int) bottomDeltaLength; 115 int childLeftMargin = (int) leftDeltaLength; 116 int childRightMargin = (int) rightDeltaLength; 117 int childTopMargin = (int) topDeltaLength; 118 int widthMeasureSpecMode; 119 int widthMeasureSpecSize; 120 int heightMeasureSpecMode; 121 int heightMeasureSpecSize; 122 if (widthMode == MeasureSpec.UNSPECIFIED) { 123 widthMeasureSpecMode = MeasureSpec.UNSPECIFIED; 124 widthMeasureSpecSize = MeasureSpec.getSize(widthMeasureSpec); 125 } else { 126 if (layoutParams.width == ShadowLayoutParams.MATCH_PARENT) { 127 widthMeasureSpecMode = MeasureSpec.EXACTLY; 128 widthMeasureSpecSize = measuredWidth - childLeftMargin - childRightMargin; 129 } else if (ShadowLayoutParams.WRAP_CONTENT == layoutParams.width) { 130 widthMeasureSpecMode = MeasureSpec.AT_MOST; 131 widthMeasureSpecSize = measuredWidth - childLeftMargin - childRightMargin; 132 } else { 133 widthMeasureSpecMode = MeasureSpec.EXACTLY; 134 widthMeasureSpecSize = layoutParams.width; 135 } 136 } 137 if (heightMode == MeasureSpec.UNSPECIFIED) { 138 heightMeasureSpecMode = MeasureSpec.UNSPECIFIED; 139 heightMeasureSpecSize = MeasureSpec.getSize(heightMeasureSpec); 140 } else { 141 if (layoutParams.height == ShadowLayoutParams.MATCH_PARENT) { 142 heightMeasureSpecMode = MeasureSpec.EXACTLY; 143 heightMeasureSpecSize = measuredHeight - childBottomMargin - childTopMargin; 144 } else if (ShadowLayoutParams.WRAP_CONTENT == layoutParams.height) { 145 heightMeasureSpecMode = MeasureSpec.AT_MOST; 146 heightMeasureSpecSize = measuredHeight - childBottomMargin - childTopMargin; 147 } else { 148 heightMeasureSpecMode = MeasureSpec.EXACTLY; 149 heightMeasureSpecSize = layoutParams.height; 150 } 151 } 152 measureChild(child, MeasureSpec.makeMeasureSpec(widthMeasureSpecSize, widthMeasureSpecMode), MeasureSpec.makeMeasureSpec(heightMeasureSpecSize, heightMeasureSpecMode)); 153 int parentWidthMeasureSpec = MeasureSpec.getMode(widthMeasureSpec); 154 int parentHeightMeasureSpec = MeasureSpec.getMode(heightMeasureSpec); 155 int height = measuredHeight; 156 int width = measuredWidth; 157 int childHeight = child.getMeasuredHeight(); 158 int childWidth = child.getMeasuredWidth(); 159 if (parentHeightMeasureSpec == MeasureSpec.AT_MOST) { 160 height = childHeight + childTopMargin + childBottomMargin; 161 } 162 if (parentWidthMeasureSpec == MeasureSpec.AT_MOST) { 163 width = childWidth + childRightMargin + childLeftMargin; 164 } 165 if (width < childWidth + leftDeltaLength + rightDeltaLength) { 166 width = (int) (childWidth + leftDeltaLength + rightDeltaLength); 167 } 168 if (height < childHeight + topDeltaLength + bottomDeltaLength) { 169 height = (int) (childHeight + topDeltaLength + bottomDeltaLength); 170 } 171 if (height != measuredHeight || width != measuredWidth) { 172 setMeasuredDimension(width, height); 173 } 174 } 175 176 public static class ShadowLayoutParams extends MarginLayoutParams { 177 178 public ShadowLayoutParams(Context c, AttributeSet attrs) { 179 super(c, attrs); 180 } 181 182 public ShadowLayoutParams(int width, int height) { 183 super(width, height); 184 } 185 186 public ShadowLayoutParams(MarginLayoutParams source) { 187 super(source); 188 } 189 190 public ShadowLayoutParams(ViewGroup.LayoutParams source) { 191 super(source); 192 } 193 } 194 195 @Override 196 protected ViewGroup.LayoutParams generateDefaultLayoutParams() { 197 return new ShadowLayoutParams(ShadowLayoutParams.WRAP_CONTENT, ShadowLayoutParams.WRAP_CONTENT); 198 } 199 200 @Override 201 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 202 return new ShadowLayoutParams(p); 203 } 204 205 @Override 206 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { 207 return new ShadowLayoutParams(getContext(), attrs); 208 } 209 210 @Override 211 protected void onLayout(boolean changed, int l, int t, int r, int b) { 212 View child = getChildAt(0); 213 int measuredWidth = getMeasuredWidth(); 214 int measuredHeight = getMeasuredHeight(); 215 int childMeasureWidth = child.getMeasuredWidth(); 216 int childMeasureHeight = child.getMeasuredHeight(); 217 // child.layout((measuredWidth - childMeasureWidth) / 2, (measuredHeight - childMeasureHeight) / 2, (measuredWidth + childMeasureWidth) / 2, (measuredHeight + childMeasureHeight) / 2); 218 child.layout((int) leftDeltaLength, (int) topDeltaLength, (int) (leftDeltaLength + childMeasureWidth), (int) (topDeltaLength + childMeasureHeight)); 219 } 220 }
使用方式:
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 android:orientation="vertical"> 8 9 <FrameLayout 10 android:id="@+id/top" 11 android:layout_width="wrap_content" 12 android:layout_height="wrap_content" 13 android:layout_marginTop="10dp" 14 android:layout_marginRight="10dp" 15 android:visibility="gone"> 16 17 <View 18 android:id="@+id/layer" 19 android:layout_width="match_parent" 20 android:layout_height="200dp" 21 android:background="#7fff00ff" /> 22 23 <TextView 24 android:id="@+id/tv" 25 android:layout_width="wrap_content" 26 android:layout_height="wrap_content" 27 android:layout_marginLeft="10dp" 28 android:layout_marginTop="10dp" 29 android:text="默认竖屏" 30 android:textColor="#00ff00" 31 android:textSize="23sp" /> 32 33 <TextView 34 android:layout_width="wrap_content" 35 android:layout_height="wrap_content" 36 android:layout_gravity="top|right" 37 android:layout_marginTop="10dp" 38 android:layout_marginRight="10dp" 39 android:text="右上角" 40 android:textColor="#00ff00" 41 android:textSize="23sp" /> 42 43 <TextView 44 android:id="@+id/btn" 45 android:layout_width="wrap_content" 46 android:layout_height="wrap_content" 47 android:layout_gravity="bottom|right" 48 android:layout_marginRight="10dp" 49 android:layout_marginBottom="10dp" 50 android:text="点击" 51 android:textColor="#00ff00" 52 android:textSize="23sp" /> 53 </FrameLayout> 54 55 <LinearLayout 56 android:layout_width="wrap_content" 57 android:layout_height="wrap_content" 58 android:layout_alignParentBottom="true" 59 android:layout_centerHorizontal="true" 60 android:background="@drawable/ala_wish_list_bg" 61 android:orientation="vertical" 62 android:padding="30dp"> 63 64 <TextView 65 android:layout_width="wrap_content" 66 android:layout_height="wrap_content" 67 android:text="四周等距离发散阴影" /> 68 69 <com.example.android_research.ShadowContainer 70 android:layout_width="wrap_content" 71 android:layout_height="wrap_content" 72 app:bottomDeltaLength="12dp" 73 app:containerCornerRadius="13dp" 74 app:containerShadowColor="#70B5041A" 75 app:containerShadowRadius="6dp" 76 app:leftDeltaLength="12dp" 77 app:rightDeltaLength="12dp" 78 app:topDeltaLength="12dp"> 79 80 <TextView 81 android:layout_width="match_parent" 82 android:layout_height="100dp" 83 android:background="@drawable/ala_my_wish_list_item_bg" /> 84 </com.example.android_research.ShadowContainer> 85 86 <TextView 87 android:layout_width="wrap_content" 88 android:layout_height="wrap_content" 89 android:layout_marginTop="30dp" 90 android:text="底部阴影区较大,顶部及两侧较小" /> 91 92 <com.example.android_research.ShadowContainer 93 android:layout_width="wrap_content" 94 android:layout_height="wrap_content" 95 app:bottomDeltaLength="12dp" 96 app:containerCornerRadius="13dp" 97 app:containerShadowColor="#70B5041A" 98 app:containerShadowRadius="6dp" 99 app:deltaY="3dp" 100 app:leftDeltaLength="4dp" 101 app:rightDeltaLength="4dp" 102 app:topDeltaLength="4dp"> 103 104 <TextView 105 android:layout_width="match_parent" 106 android:layout_height="100dp" 107 android:background="@drawable/ala_my_wish_list_item_bg" /> 108 </com.example.android_research.ShadowContainer> 109 110 111 <TextView 112 android:layout_width="wrap_content" 113 android:layout_height="wrap_content" 114 android:layout_marginTop="30dp" 115 android:text="圆形右下角运营区" /> 116 117 <com.example.android_research.ShadowContainer 118 android:layout_width="wrap_content" 119 android:layout_height="wrap_content" 120 app:bottomDeltaLength="10dp" 121 app:containerCornerRadius="80dp" 122 app:containerShadowColor="#ffff00" 123 app:containerShadowRadius="6dp" 124 app:deltaX="3dp" 125 app:deltaY="6dp" 126 app:rightDeltaLength="10dp" 127 app:topDeltaLength="0dp"> 128 129 <TextView 130 android:layout_width="100dp" 131 android:layout_height="100dp" 132 android:background="@drawable/circle" /> 133 </com.example.android_research.ShadowContainer> 134 </LinearLayout> 135 136 137 </RelativeLayout>