Android 列表项上的滑动菜单无法处理父宽度更改
Android Swipe menu on list item can't handle parent width changes
我正在尝试为我在 recyclerview 中的项目创建滑动菜单并最终实现了库:https://github.com/chthai64/SwipeRevealLayout
实施后初看,还以为可以呢。但出于某种原因,当父级 view/layout(包含片段的框架布局)发生变化时,它 change/measure/layout 项目的正确宽度不正确。
该项目只是保持相同的宽度,太宽或太短,具体取决于父视图的缩放方式。
我已经从库中的自定义视图 "SwipeRevealLayout" 中包含了 onMeasure 方法。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getChildCount() < 2) {
throw new RuntimeException("Layout must have two children");
}
final LayoutParams params = getLayoutParams();
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int desiredWidth = 0;
int desiredHeight = 0;
// first find the largest child
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
}
// create new measure spec using the largest child width
widthMeasureSpec = MeasureSpec.makeMeasureSpec(desiredWidth, widthMode);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(desiredHeight, heightMode);
final int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
final int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
final LayoutParams childParams = child.getLayoutParams();
if (childParams != null) {
if (childParams.height == LayoutParams.MATCH_PARENT) {
child.setMinimumHeight(measuredHeight);
}
if (childParams.width == LayoutParams.MATCH_PARENT) {
child.setMinimumWidth(measuredWidth);
}
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
}
// taking accounts of padding
desiredWidth += getPaddingLeft() + getPaddingRight();
desiredHeight += getPaddingTop() + getPaddingBottom();
// adjust desired width
if (widthMode == MeasureSpec.EXACTLY) {
desiredWidth = measuredWidth;
} else {
if (params.width == LayoutParams.MATCH_PARENT) {
desiredWidth = measuredWidth;
}
if (widthMode == MeasureSpec.AT_MOST) {
desiredWidth = (desiredWidth > measuredWidth)? measuredWidth : desiredWidth;
}
}
// adjust desired height
if (heightMode == MeasureSpec.EXACTLY) {
desiredHeight = measuredHeight;
} else {
if (params.height == LayoutParams.MATCH_PARENT) {
desiredHeight = measuredHeight;
}
if (heightMode == MeasureSpec.AT_MOST) {
desiredHeight = (desiredHeight > measuredHeight)? measuredHeight : desiredHeight;
}
}
setMeasuredDimension(desiredWidth, desiredHeight);
}
我在其他地方找到了部分解决方案,项目的所有内容都已正确缩放。我用下面的代码替换了 onMeasure 中的所有代码。然而,这个解决方案有一个副作用,即项目被完全擦出屏幕,而不是在滑动菜单的按钮之前停止。
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth() / 2);
// this is required because the children keep the super class calculated dimensions (which will not work with the new MyFrameLayout sizes)
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View v = getChildAt(i);
v.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMeasuredHeight(), MeasureSpec.EXACTLY));
}
没关系:)我终于通过在onMeasure中操纵项目的宽度解决了这个问题。
这对我来说很完美。也许其他人可以使用它。
我所做的是检查第一个子项是否比我允许的宽(比父视图宽),如果是,则将其设置为最大宽度。
如果其他子视图(例如列表中的项目)的 width/measured 宽度不等于父视图宽度,我将子视图设置为此。
这里是onMeasure的顶部,我稍微改了一下。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getChildCount() < 2) {
throw new RuntimeException("Layout must have two children");
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final LayoutParams params = getLayoutParams();
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int maxWidth = getMeasuredWidth();
int desiredWidth = 0;
int desiredHeight = 0;
// first find the largest child
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
if (i == 0 && (child.getWidth() > maxWidth || child.getMeasuredWidth() > maxWidth)
|| i > 0 && (child.getWidth() != maxWidth || child.getMeasuredWidth() != maxWidth)) {
LayoutParams lm = child.getLayoutParams();
lm.width = maxWidth;
child.setLayoutParams(lm);
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
}
...
我正在尝试为我在 recyclerview 中的项目创建滑动菜单并最终实现了库:https://github.com/chthai64/SwipeRevealLayout
实施后初看,还以为可以呢。但出于某种原因,当父级 view/layout(包含片段的框架布局)发生变化时,它 change/measure/layout 项目的正确宽度不正确。
该项目只是保持相同的宽度,太宽或太短,具体取决于父视图的缩放方式。
我已经从库中的自定义视图 "SwipeRevealLayout" 中包含了 onMeasure 方法。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getChildCount() < 2) {
throw new RuntimeException("Layout must have two children");
}
final LayoutParams params = getLayoutParams();
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int desiredWidth = 0;
int desiredHeight = 0;
// first find the largest child
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
}
// create new measure spec using the largest child width
widthMeasureSpec = MeasureSpec.makeMeasureSpec(desiredWidth, widthMode);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(desiredHeight, heightMode);
final int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
final int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
final LayoutParams childParams = child.getLayoutParams();
if (childParams != null) {
if (childParams.height == LayoutParams.MATCH_PARENT) {
child.setMinimumHeight(measuredHeight);
}
if (childParams.width == LayoutParams.MATCH_PARENT) {
child.setMinimumWidth(measuredWidth);
}
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
}
// taking accounts of padding
desiredWidth += getPaddingLeft() + getPaddingRight();
desiredHeight += getPaddingTop() + getPaddingBottom();
// adjust desired width
if (widthMode == MeasureSpec.EXACTLY) {
desiredWidth = measuredWidth;
} else {
if (params.width == LayoutParams.MATCH_PARENT) {
desiredWidth = measuredWidth;
}
if (widthMode == MeasureSpec.AT_MOST) {
desiredWidth = (desiredWidth > measuredWidth)? measuredWidth : desiredWidth;
}
}
// adjust desired height
if (heightMode == MeasureSpec.EXACTLY) {
desiredHeight = measuredHeight;
} else {
if (params.height == LayoutParams.MATCH_PARENT) {
desiredHeight = measuredHeight;
}
if (heightMode == MeasureSpec.AT_MOST) {
desiredHeight = (desiredHeight > measuredHeight)? measuredHeight : desiredHeight;
}
}
setMeasuredDimension(desiredWidth, desiredHeight);
}
我在其他地方找到了部分解决方案,项目的所有内容都已正确缩放。我用下面的代码替换了 onMeasure 中的所有代码。然而,这个解决方案有一个副作用,即项目被完全擦出屏幕,而不是在滑动菜单的按钮之前停止。
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth() / 2);
// this is required because the children keep the super class calculated dimensions (which will not work with the new MyFrameLayout sizes)
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View v = getChildAt(i);
v.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMeasuredHeight(), MeasureSpec.EXACTLY));
}
没关系:)我终于通过在onMeasure中操纵项目的宽度解决了这个问题。 这对我来说很完美。也许其他人可以使用它。 我所做的是检查第一个子项是否比我允许的宽(比父视图宽),如果是,则将其设置为最大宽度。 如果其他子视图(例如列表中的项目)的 width/measured 宽度不等于父视图宽度,我将子视图设置为此。
这里是onMeasure的顶部,我稍微改了一下。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getChildCount() < 2) {
throw new RuntimeException("Layout must have two children");
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final LayoutParams params = getLayoutParams();
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int maxWidth = getMeasuredWidth();
int desiredWidth = 0;
int desiredHeight = 0;
// first find the largest child
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
if (i == 0 && (child.getWidth() > maxWidth || child.getMeasuredWidth() > maxWidth)
|| i > 0 && (child.getWidth() != maxWidth || child.getMeasuredWidth() != maxWidth)) {
LayoutParams lm = child.getLayoutParams();
lm.width = maxWidth;
child.setLayoutParams(lm);
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
desiredWidth = Math.max(child.getMeasuredWidth(), desiredWidth);
desiredHeight = Math.max(child.getMeasuredHeight(), desiredHeight);
}
...