Android:fix ListItem cannot clip corner or draw shadow

This commit is contained in:
pengfei.zhou 2021-09-02 17:46:26 +08:00 committed by osborn
parent 15172bb653
commit 627c107976
5 changed files with 176 additions and 160 deletions

View File

@ -21,22 +21,17 @@ import android.graphics.Paint;
import android.graphics.Path; import android.graphics.Path;
import android.graphics.RectF; import android.graphics.RectF;
import android.graphics.Region; import android.graphics.Region;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
/** /**
* @Description: com.github.penfeizhou.doric.shader * @Description: com.github.penfeizhou.doric.shader
* @Author: pengfei.zhou * @Author: pengfei.zhou
* @CreateDate: 2019-07-31 * @CreateDate: 2019-07-31
*/ */
public class DoricLayer extends FrameLayout { public class DoricLayer extends MaximumFrameLayout {
private final Path mCornerPath = new Path(); private final Path mCornerPath = new Path();
private Paint mShadowPaint; private Paint mShadowPaint;
private Paint mBorderPaint; private Paint mBorderPaint;
@ -47,19 +42,6 @@ public class DoricLayer extends FrameLayout {
super(context); super(context);
} }
public DoricLayer(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public DoricLayer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public DoricLayer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
super.onDraw(canvas); super.onDraw(canvas);
@ -67,6 +49,16 @@ public class DoricLayer extends FrameLayout {
@Override @Override
public void draw(Canvas canvas) { public void draw(Canvas canvas) {
mRect.left = 0;
mRect.right = getWidth();
mRect.top = 0;
mRect.bottom = getHeight();
if (mCornerRadii != null) {
canvas.save();
mCornerPath.reset();
mCornerPath.addRoundRect(mRect, mCornerRadii, Path.Direction.CW);
canvas.clipPath(mCornerPath);
}
super.draw(canvas); super.draw(canvas);
} }
@ -81,6 +73,9 @@ public class DoricLayer extends FrameLayout {
mRect.right = getWidth(); mRect.right = getWidth();
mRect.top = 0; mRect.top = 0;
mRect.bottom = getHeight(); mRect.bottom = getHeight();
if (canvas.getSaveCount() > 1) {
canvas.restore();
}
canvas.save(); canvas.save();
if (mCornerRadii != null) { if (mCornerRadii != null) {
mCornerPath.reset(); mCornerPath.reset();

View File

@ -0,0 +1,158 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package pub.doric.shader;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.FrameLayout;
import java.util.ArrayList;
/**
* @Description: MaximumFrameLayout
* @Author: pengfei.zhou
* @CreateDate: 2021/9/2
*/
class MaximumFrameLayout extends FrameLayout {
int maxWidth = Integer.MAX_VALUE;
int maxHeight = Integer.MAX_VALUE;
private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
public MaximumFrameLayout(Context context) {
super(context);
}
int getPaddingLeftWithForeground() {
return getPaddingLeft();
}
int getPaddingRightWithForeground() {
return getPaddingRight();
}
private int getPaddingTopWithForeground() {
return getPaddingTop();
}
private int getPaddingBottomWithForeground() {
return getPaddingBottom();
}
private void rawOnMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
final boolean measureMatchParentChildren =
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
mMatchParentChildren.clear();
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (getMeasureAllChildren() || child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
if (measureMatchParentChildren) {
if (lp.width == LayoutParams.MATCH_PARENT ||
lp.height == LayoutParams.MATCH_PARENT) {
mMatchParentChildren.add(child);
}
}
}
}
// Account for padding too
maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
// Check against our foreground's minimum height and width
final Drawable drawable = getForeground();
if (drawable != null) {
maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
}
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState << MEASURED_HEIGHT_STATE_SHIFT));
count = mMatchParentChildren.size();
if (count > 0) {
for (int i = 0; i < count; i++) {
final View child = mMatchParentChildren.get(i);
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int childWidthMeasureSpec;
if (lp.width == LayoutParams.MATCH_PARENT) {
final int width = Math.max(0, getMeasuredWidth()
- getPaddingLeftWithForeground() - getPaddingRightWithForeground()
- lp.leftMargin - lp.rightMargin);
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
width, MeasureSpec.EXACTLY);
} else {
childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
lp.leftMargin + lp.rightMargin,
lp.width);
}
final int childHeightMeasureSpec;
if (lp.height == LayoutParams.MATCH_PARENT) {
final int height = Math.max(0, getMeasuredHeight()
- getPaddingTopWithForeground() - getPaddingBottomWithForeground()
- lp.topMargin - lp.bottomMargin);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
height, MeasureSpec.EXACTLY);
} else {
childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
lp.topMargin + lp.bottomMargin,
lp.height);
}
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
rawOnMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
if (width > maxWidth || height > maxHeight) {
width = Math.min(width, maxWidth);
height = Math.min(height, maxHeight);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
rawOnMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}

View File

@ -15,9 +15,6 @@
*/ */
package pub.doric.shader; package pub.doric.shader;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@ -28,8 +25,6 @@ import pub.doric.utils.DoricUtils;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JSValue;
import java.util.ArrayList;
/** /**
* @Description: com.github.penfeizhou.doric.widget * @Description: com.github.penfeizhou.doric.widget
* @Author: pengfei.zhou * @Author: pengfei.zhou
@ -37,136 +32,6 @@ import java.util.ArrayList;
*/ */
@DoricPlugin(name = "Stack") @DoricPlugin(name = "Stack")
public class StackNode extends GroupNode<FrameLayout> { public class StackNode extends GroupNode<FrameLayout> {
private static class MaximumFrameLayout extends FrameLayout {
private int maxWidth = Integer.MAX_VALUE;
private int maxHeight = Integer.MAX_VALUE;
private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
public MaximumFrameLayout(Context context) {
super(context);
}
int getPaddingLeftWithForeground() {
return getPaddingLeft();
}
int getPaddingRightWithForeground() {
return getPaddingRight();
}
private int getPaddingTopWithForeground() {
return getPaddingTop();
}
private int getPaddingBottomWithForeground() {
return getPaddingBottom();
}
private void rawOnMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
final boolean measureMatchParentChildren =
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
mMatchParentChildren.clear();
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (getMeasureAllChildren() || child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
if (measureMatchParentChildren) {
if (lp.width == LayoutParams.MATCH_PARENT ||
lp.height == LayoutParams.MATCH_PARENT) {
mMatchParentChildren.add(child);
}
}
}
}
// Account for padding too
maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
// Check against our foreground's minimum height and width
final Drawable drawable = getForeground();
if (drawable != null) {
maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
}
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState << MEASURED_HEIGHT_STATE_SHIFT));
count = mMatchParentChildren.size();
if (count > 0) {
for (int i = 0; i < count; i++) {
final View child = mMatchParentChildren.get(i);
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int childWidthMeasureSpec;
if (lp.width == LayoutParams.MATCH_PARENT) {
final int width = Math.max(0, getMeasuredWidth()
- getPaddingLeftWithForeground() - getPaddingRightWithForeground()
- lp.leftMargin - lp.rightMargin);
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
width, MeasureSpec.EXACTLY);
} else {
childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
lp.leftMargin + lp.rightMargin,
lp.width);
}
final int childHeightMeasureSpec;
if (lp.height == LayoutParams.MATCH_PARENT) {
final int height = Math.max(0, getMeasuredHeight()
- getPaddingTopWithForeground() - getPaddingBottomWithForeground()
- lp.topMargin - lp.bottomMargin);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
height, MeasureSpec.EXACTLY);
} else {
childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
lp.topMargin + lp.bottomMargin,
lp.height);
}
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
rawOnMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
if (width > maxWidth || height > maxHeight) {
width = Math.min(width, maxWidth);
height = Math.min(height, maxHeight);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
rawOnMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
public StackNode(DoricContext doricContext) { public StackNode(DoricContext doricContext) {
super(doricContext); super(doricContext);
@ -196,7 +61,7 @@ public class StackNode extends GroupNode<FrameLayout> {
@Override @Override
protected FrameLayout build() { protected FrameLayout build() {
return new MaximumFrameLayout(getContext()); return new DoricLayer(getContext());
} }
@Override @Override

View File

@ -36,7 +36,6 @@ import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator; import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator; import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.DoricLinearLayoutCompat; import androidx.appcompat.widget.DoricLinearLayoutCompat;
@ -543,6 +542,9 @@ public abstract class ViewNode<T extends View> extends DoricContextHolder {
@NonNull @NonNull
private DoricLayer requireDoricLayer() { private DoricLayer requireDoricLayer() {
if (mView instanceof DoricLayer) {
return (DoricLayer) mView;
}
if (doricLayer == null) { if (doricLayer == null) {
doricLayer = new DoricLayer(getContext()); doricLayer = new DoricLayer(getContext());
doricLayer.setLayoutParams(mLayoutParams); doricLayer.setLayoutParams(mLayoutParams);

View File

@ -15,12 +15,8 @@
*/ */
package pub.doric.shader.list; package pub.doric.shader.list;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import com.github.pengfeizhou.jscore.JSArray;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JSValue;