无法在android react native模块中调整线性布局子元素的大小 [英] Cannot resize linear layout children in android react native module

查看:148
本文介绍了无法在android react native模块中调整线性布局子元素的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

完整代码在此处

在Java中行为正确且在本机反应不正确的视频

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

    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都没有任何效果.

我还需要调用其他一些代码来使视图无效并重画视图吗?我需要给我一个提示,以提示该组件滚动或响应触摸吗?

解决方案

在大多数情况下,RN android确实不会更新子级布局,可见性或适配器更改.通过在需要更新时将挂钩插入自定义视图中,该更新将使/requestLayout无效/然后调用此代码,通常可以恢复正常行为.在某些情况下,无法正常进行测量,因此我不得不发布Delayed Runnables,这会导致这种失效.并非在所有情况下都严格要求与节点的父母打交道,但在某些情况下是必须的.

在View Manager中

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


    }

Full code here

Video of correct behavior in java and incorrect in react native here

I have modified a linear layout to respond to touch by resizing the left child while the right child takes up the rest of the space, simulating a horizontal scroll that can be 'opened' or 'closed' using the following code

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

In react native, touch is still calling this method and logging the expected values, but the size of the children is not updated. The only time it updates is when I switch the visibility to gone then visible again. Calling invalidate/requestLayout on the view from java or forceUpdate from js does not have any effect.

Is there some other code I need to call to invalidate and redraw the view? Is there a hint I need to give to react that this component scrolls or responds to touch?

解决方案

RN android is indeed not updating children layout or visibility or adapter changes under most conditions. By inserting hooks into the custom view when an update is needed that will invalidate/requestLayout then call this code normal behavior is restored, mostly. There are still some cases where measurement does not happen like it does normally and I have to postDelayed Runnables that then cause this invalidation. Dealing with a node's parents may not be strictly necessary in all cases, but it is for some.

In View Manager

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


    }

这篇关于无法在android react native模块中调整线性布局子元素的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆