Cannot resize linear layout children in android react native module

前端 未结 4 872
清酒与你
清酒与你 2021-02-13 21:31

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 chil

相关标签:
4条回答
  • 2021-02-13 21:44

    Try removing content of the layout one by one. May be one among those children has wrap content. You can use hierarchyViewer and uiautomatorviewer for it Also think about weights also. If possible post the hierarchyViewer data.

    0 讨论(0)
  • 2021-02-13 21:46
    LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) leftView.getLayoutParams();
    lp.width=newWidth;
    leftView.setLayoutParams(lp);
    leftView.requestLayout(); 
    

    Above code will solve you problem.

    0 讨论(0)
  • 2021-02-13 21:48

    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);
                }
            });
    
    
        }
    
    0 讨论(0)
  • 2021-02-13 21:59

    I had the same problem and I found the answer on this old reported issue on react native's repo.

    Add the following code in your custom layout and after that there is no need to even call requestLayout() or invalidate(). The changes are propagated as soon as you update your layout's LayoutParams. This solution is the same as the ones used in 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());
        }
    };
    
    0 讨论(0)
提交回复
热议问题