无法在 android 反应本机模块中调整线性布局子项的大小
Cannot resize linear layout children in android react native module
Video of correct behavior in java and incorrect in react native here
我修改了一个线性布局,通过调整左子元素的大小来响应触摸,而右子元素占据 space 的其余部分,模拟水平滚动,可以是 'opened' 或 'closed' 使用下面的代码
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) leftView.getLayoutParams();
//Log.d("ll","width " + newWidth);
lp.width=newWidth;
leftView.setLayoutParams(lp);
在 react native 中,touch 仍在调用此方法并记录预期值,但未更新子项的大小。它唯一更新的时间是当我将可见性切换为消失然后再次可见时。从 java 调用视图上的 invalidate/requestLayout 或从 js 调用 forceUpdate 没有任何效果。
是否需要调用其他代码来使视图无效并重绘?是否有提示我需要给出该组件滚动或响应触摸的反应?
尝试一项一项地删除版面的内容。可能是 children 具有换行内容的其中之一。您可以为此使用 hierarchyViewer 和 uiautomatorviewer
还要考虑重量。如果可能 post hierarchyViewer 数据。
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) leftView.getLayoutParams();
lp.width=newWidth;
leftView.setLayoutParams(lp);
leftView.requestLayout();
以上代码可以解决您的问题。
RN android 在大多数情况下确实不会更新子布局或可见性或适配器更改。通过在需要更新时将挂钩插入自定义视图,然后调用此代码通常会恢复正常行为。在某些情况下,测量不会像正常情况那样发生,我必须发布延迟运行,然后导致此无效。处理节点的父节点可能并非在所有情况下都是绝对必要的,但对于某些情况是这样。
在视图管理器中
Method markNewLayout, getShadowNode;
public ViewManager(){
super();
if (markNewLayout == null) {
try {
markNewLayout = CSSNode.class.getDeclaredMethod("markHasNewLayout");
markNewLayout.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
try{
if (getShadowNode==null){
getShadowNode = UIImplementation.class.getDeclaredMethod("resolveShadowNode",int.class);
getShadowNode.setAccessible(true);
}
} catch (Exception e) {
e.printStackTrace();
}
public class MyShadowNode extends LayoutShadowNode {
@Override
public void markUpdated(){
super.markUpdated();
if (hasNewLayout()) markLayoutSeen();
dirty();
}
@Override
public boolean isDirty(){
return true;
}
@Override
protected CustomView createViewInstance(final ThemedReactContext reactContext) {
view.setRnUpdateListener(new CustomView.RNUpdateListener() {
MyShadowNode node;
@Override
public void needsUpdate() {
view.requestLayout();
Runnable r = new Runnable() {
@Override
public void run() {
if (node ==null){
try {
node = (MyShadowNode) getShadowNode.invoke(uiImplementation, view.getId());
}
catch (Exception e){
e.printStackTrace();
}
}
if (node != null) {
if (node.hasNewLayout()) node.markLayoutSeen();
ReactShadowNode parent = node.getParent();
while (parent != null) {
if (parent.hasNewLayout()) {
try {
markNewLayout.invoke(parent,view.getId());
} catch (Exception e) {
e.printStackTrace();
}
parent.markLayoutSeen();
}
parent = parent.getParent();
}
node.markUpdated();
}
Log.d(getName(), "markUpdated");
}
};
reactContext.runOnNativeModulesQueueThread(r);
}
});
}
我遇到了同样的问题,我在 this React Native 存储库的旧报告问题上找到了答案。
在您的自定义布局中添加以下代码,之后甚至不需要调用 requestLayout() 或 invalidate()。一旦您更新布局的 LayoutParams,更改就会传播。此解决方案与 ReactPicker.java and ReactToolbar.java 中使用的解决方案相同。
@Override
public void requestLayout() {
super.requestLayout();
// The spinner relies on a measure + layout pass happening after it calls requestLayout().
// Without this, the widget never actually changes the selection and doesn't call the
// appropriate listeners. Since we override onLayout in our ViewGroups, a layout pass never
// happens after a call to requestLayout, so we simulate one here.
post(measureAndLayout);
}
private final Runnable measureAndLayout = new Runnable() {
@Override
public void run() {
measure(
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
}
};
Video of correct behavior in java and incorrect in react native here
我修改了一个线性布局,通过调整左子元素的大小来响应触摸,而右子元素占据 space 的其余部分,模拟水平滚动,可以是 'opened' 或 'closed' 使用下面的代码
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) leftView.getLayoutParams();
//Log.d("ll","width " + newWidth);
lp.width=newWidth;
leftView.setLayoutParams(lp);
在 react native 中,touch 仍在调用此方法并记录预期值,但未更新子项的大小。它唯一更新的时间是当我将可见性切换为消失然后再次可见时。从 java 调用视图上的 invalidate/requestLayout 或从 js 调用 forceUpdate 没有任何效果。
是否需要调用其他代码来使视图无效并重绘?是否有提示我需要给出该组件滚动或响应触摸的反应?
尝试一项一项地删除版面的内容。可能是 children 具有换行内容的其中之一。您可以为此使用 hierarchyViewer 和 uiautomatorviewer 还要考虑重量。如果可能 post hierarchyViewer 数据。
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) leftView.getLayoutParams();
lp.width=newWidth;
leftView.setLayoutParams(lp);
leftView.requestLayout();
以上代码可以解决您的问题。
RN android 在大多数情况下确实不会更新子布局或可见性或适配器更改。通过在需要更新时将挂钩插入自定义视图,然后调用此代码通常会恢复正常行为。在某些情况下,测量不会像正常情况那样发生,我必须发布延迟运行,然后导致此无效。处理节点的父节点可能并非在所有情况下都是绝对必要的,但对于某些情况是这样。
在视图管理器中
Method markNewLayout, getShadowNode;
public ViewManager(){
super();
if (markNewLayout == null) {
try {
markNewLayout = CSSNode.class.getDeclaredMethod("markHasNewLayout");
markNewLayout.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
try{
if (getShadowNode==null){
getShadowNode = UIImplementation.class.getDeclaredMethod("resolveShadowNode",int.class);
getShadowNode.setAccessible(true);
}
} catch (Exception e) {
e.printStackTrace();
}
public class MyShadowNode extends LayoutShadowNode {
@Override
public void markUpdated(){
super.markUpdated();
if (hasNewLayout()) markLayoutSeen();
dirty();
}
@Override
public boolean isDirty(){
return true;
}
@Override
protected CustomView createViewInstance(final ThemedReactContext reactContext) {
view.setRnUpdateListener(new CustomView.RNUpdateListener() {
MyShadowNode node;
@Override
public void needsUpdate() {
view.requestLayout();
Runnable r = new Runnable() {
@Override
public void run() {
if (node ==null){
try {
node = (MyShadowNode) getShadowNode.invoke(uiImplementation, view.getId());
}
catch (Exception e){
e.printStackTrace();
}
}
if (node != null) {
if (node.hasNewLayout()) node.markLayoutSeen();
ReactShadowNode parent = node.getParent();
while (parent != null) {
if (parent.hasNewLayout()) {
try {
markNewLayout.invoke(parent,view.getId());
} catch (Exception e) {
e.printStackTrace();
}
parent.markLayoutSeen();
}
parent = parent.getParent();
}
node.markUpdated();
}
Log.d(getName(), "markUpdated");
}
};
reactContext.runOnNativeModulesQueueThread(r);
}
});
}
我遇到了同样的问题,我在 this React Native 存储库的旧报告问题上找到了答案。
在您的自定义布局中添加以下代码,之后甚至不需要调用 requestLayout() 或 invalidate()。一旦您更新布局的 LayoutParams,更改就会传播。此解决方案与 ReactPicker.java and ReactToolbar.java 中使用的解决方案相同。
@Override
public void requestLayout() {
super.requestLayout();
// The spinner relies on a measure + layout pass happening after it calls requestLayout().
// Without this, the widget never actually changes the selection and doesn't call the
// appropriate listeners. Since we override onLayout in our ViewGroups, a layout pass never
// happens after a call to requestLayout, so we simulate one here.
post(measureAndLayout);
}
private final Runnable measureAndLayout = new Runnable() {
@Override
public void run() {
measure(
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
}
};