12

完整代码在这里

java中正确行为的视频和react Native中的错误视频here

我修改了一个线性布局,通过调整左孩子的大小而右孩子占据其余空间来响应触摸,使用以下代码模拟可以“打开”或“关闭”的水平滚动

    LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) leftView.getLayoutParams();
    //Log.d("ll","width " + newWidth);
    lp.width=newWidth;
    leftView.setLayoutParams(lp);

在 react native 中,touch 仍在调用此方法并记录预期值,但子项的大小并未更新。它更新的唯一时间是当我将可见性切换为消失然后再次可见时。从 java 或从 js 对视图调用 invalidate/requestLayout 或从 js 调用 forceUpdate 没有任何效果。

我需要调用其他代码来使视图无效并重绘视图吗?我需要给出提示以响应此组件滚动或响应触摸吗?

4

4 回答 4

7

我遇到了同样的问题,我在 react native 的 repo 上找到了这个旧报告问题的答案。

在您的自定义布局中添加以下代码,之后甚至不需要调用 requestLayout() 或 invalidate()。更新布局的 LayoutParams 后,更改就会立即传播。此解决方案与ReactPicker.javaReactToolbar.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());
    }
};
于 2016-10-03T19:55:41.913 回答
1

在大多数情况下,RN android 确实不会更新子布局或可见性或适配器更改。通过在需要更新时将钩子插入自定义视图,这将使/requestLayout 无效,然后调用此代码,通常会恢复正常行为。在某些情况下,测量不会像正常情况那样发生,我必须发布延迟的 Runnables,然后导致这种失效。处理节点的父节点可能并非在所有情况下都是绝对必要的,但对于某些情况来说确实如此。

在视图管理器中

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);
            }
        });


    }
于 2016-08-23T15:48:27.003 回答
0

尝试一一删除布局的内容。可能是这些孩子中的一个有包装内容。您可以使用 hierarchyViewer 和 uiautomatorviewer 也可以考虑权重。如果可能,发布 hierarchyViewer 数据。

于 2016-08-19T04:31:14.787 回答
0
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) leftView.getLayoutParams();
lp.width=newWidth;
leftView.setLayoutParams(lp);
leftView.requestLayout(); 

上面的代码会解决你的问题。

于 2016-08-22T13:17:55.783 回答