/** Releases all references to given native View. */ private void dropView(View view) { UiThreadUtil.assertOnUiThread(); if (!mRootTags.get(view.getId())) { // For non-root views we notify viewmanager with {@link ViewManager#onDropInstance} Assertions.assertNotNull(mTagsToViewManagers.get(view.getId())) .onDropViewInstance((ThemedReactContext) view.getContext(), view); } ViewManager viewManager = mTagsToViewManagers.get(view.getId()); if (view instanceof ViewGroup && viewManager instanceof ViewGroupManager) { ViewGroup viewGroup = (ViewGroup) view; ViewGroupManager viewGroupManager = (ViewGroupManager) viewManager; for (int i = viewGroupManager.getChildCount(viewGroup) - 1; i >= 0; i--) { View child = viewGroupManager.getChildAt(viewGroup, i); if (mTagsToViews.get(child.getId()) != null) { dropView(child); } } viewGroupManager.removeAllViews(viewGroup); } mTagsToViews.remove(view.getId()); mTagsToViewManagers.remove(view.getId()); }
/** * @param tag react tag of the node we want to manage * @param indicesToRemove ordered (asc) list of indicies at which view should be removed * @param viewsToAdd ordered (asc based on mIndex property) list of tag-index pairs that represent * a view which should be added at the specified index * @param tagsToDelete list of tags corresponding to views that should be removed */ public void manageChildren( int tag, @Nullable int[] indicesToRemove, @Nullable ViewAtIndex[] viewsToAdd, @Nullable int[] tagsToDelete) { ViewGroup viewToManage = (ViewGroup) mTagsToViews.get(tag); ViewGroupManager viewManager = (ViewGroupManager) mTagsToViewManagers.get(tag); if (viewManager == null) { throw new IllegalViewOperationException("ViewManager for tag " + tag + " could not be found"); } if (viewToManage == null) { throw new IllegalViewOperationException( "Trying to manageChildren view with tag " + tag + " which doesn't exist\n detail: " + constructManageChildrenErrorMessage( viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete)); } int lastIndexToRemove = viewManager.getChildCount(viewToManage); if (indicesToRemove != null) { for (int i = indicesToRemove.length - 1; i >= 0; i--) { int indexToRemove = indicesToRemove[i]; if (indexToRemove < 0) { throw new IllegalViewOperationException( "Trying to remove a negative view index:" + indexToRemove + " view tag: " + tag + "\n detail: " + constructManageChildrenErrorMessage( viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete)); } if (indexToRemove >= viewManager.getChildCount(viewToManage)) { throw new IllegalViewOperationException( "Trying to remove a view index above child " + "count " + indexToRemove + " view tag: " + tag + "\n detail: " + constructManageChildrenErrorMessage( viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete)); } if (indexToRemove >= lastIndexToRemove) { throw new IllegalViewOperationException( "Trying to remove an out of order view index:" + indexToRemove + " view tag: " + tag + "\n detail: " + constructManageChildrenErrorMessage( viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete)); } viewManager.removeViewAt(viewToManage, indicesToRemove[i]); lastIndexToRemove = indexToRemove; } } if (viewsToAdd != null) { for (int i = 0; i < viewsToAdd.length; i++) { ViewAtIndex viewAtIndex = viewsToAdd[i]; View viewToAdd = mTagsToViews.get(viewAtIndex.mTag); if (viewToAdd == null) { throw new IllegalViewOperationException( "Trying to add unknown view tag: " + viewAtIndex.mTag + "\n detail: " + constructManageChildrenErrorMessage( viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete)); } viewManager.addView(viewToManage, viewToAdd, viewAtIndex.mIndex); } } if (tagsToDelete != null) { for (int i = 0; i < tagsToDelete.length; i++) { int tagToDelete = tagsToDelete[i]; View viewToDestroy = mTagsToViews.get(tagToDelete); if (viewToDestroy == null) { throw new IllegalViewOperationException( "Trying to destroy unknown view tag: " + tagToDelete + "\n detail: " + constructManageChildrenErrorMessage( viewToManage, viewManager, indicesToRemove, viewsToAdd, tagsToDelete)); } dropView(viewToDestroy); } } }
private static String constructManageChildrenErrorMessage( ViewGroup viewToManage, ViewGroupManager viewManager, @Nullable int[] indicesToRemove, @Nullable ViewAtIndex[] viewsToAdd, @Nullable int[] tagsToDelete) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("View tag:" + viewToManage.getId() + "\n"); stringBuilder.append(" children(" + viewManager.getChildCount(viewToManage) + "): [\n"); for (int index = 0; index < viewManager.getChildCount(viewToManage); index += 16) { for (int innerOffset = 0; ((index + innerOffset) < viewManager.getChildCount(viewToManage)) && innerOffset < 16; innerOffset++) { stringBuilder.append( viewManager.getChildAt(viewToManage, index + innerOffset).getId() + ","); } stringBuilder.append("\n"); } stringBuilder.append(" ],\n"); if (indicesToRemove != null) { stringBuilder.append(" indicesToRemove(" + indicesToRemove.length + "): [\n"); for (int index = 0; index < indicesToRemove.length; index += 16) { for (int innerOffset = 0; ((index + innerOffset) < indicesToRemove.length) && innerOffset < 16; innerOffset++) { stringBuilder.append(indicesToRemove[index + innerOffset] + ","); } stringBuilder.append("\n"); } stringBuilder.append(" ],\n"); } if (viewsToAdd != null) { stringBuilder.append(" viewsToAdd(" + viewsToAdd.length + "): [\n"); for (int index = 0; index < viewsToAdd.length; index += 16) { for (int innerOffset = 0; ((index + innerOffset) < viewsToAdd.length) && innerOffset < 16; innerOffset++) { stringBuilder.append( "[" + viewsToAdd[index + innerOffset].mIndex + "," + viewsToAdd[index + innerOffset].mTag + "],"); } stringBuilder.append("\n"); } stringBuilder.append(" ],\n"); } if (tagsToDelete != null) { stringBuilder.append(" tagsToDelete(" + tagsToDelete.length + "): [\n"); for (int index = 0; index < tagsToDelete.length; index += 16) { for (int innerOffset = 0; ((index + innerOffset) < tagsToDelete.length) && innerOffset < 16; innerOffset++) { stringBuilder.append(tagsToDelete[index + innerOffset] + ","); } stringBuilder.append("\n"); } stringBuilder.append(" ]\n"); } return stringBuilder.toString(); }