Skip to content

Commit

Permalink
Add zIndex support
Browse files Browse the repository at this point in the history
Summary:
Adds zIndex support :)

**Test Plan**

Tested the following components by adding two of each, overlapping them, and setting a high zIndex on the first of the two:

ActivityIndicator
Image
MapView
Picker
ScrollView
Slider
Switch
Text
TextInput
View
WebView

Tested on Android 4.1 and iOS 8.4. Also tested updating zIndexes on Views in my own app.

<img width="359" alt="ios activityindicator" src="https://cloud.githubusercontent.com/assets/4349082/15633473/88f842cc-257b-11e6-8539-c41c0b179f80.png">
<img width="330" alt="android activityindicator" src="https://cloud.githubusercontent.com/assets/4349082/15633475/88f95784-257b-11e6-80c0-2bf3ed836503.png">
<img width="357" alt="ios image" src="https://cloud.githubusercontent.com/assets/4349082/15633474/88f93d80-257b-11e6-9e54-4ff8e4d25f71.png">
<img width="340" alt="android image" src="https://cloud.githubusercontent.com/assets/4349082/15633478/88fd2788-257b-11e6-8c80-29078e65e808.png">
<img width="342" alt="android picker" src="ht
Closes #7825

Differential Revision: D3469374

Pulled By: lexs

fbshipit-source-id: b2b74b71d968ebf73ecfd457ace3f35f8f7c7658
  • Loading branch information
tuckerconnelly authored and Facebook Github Bot 3 committed Jun 29, 2016
1 parent 3085b35 commit 3d3b067
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 2 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions Examples/UIExplorer/ViewExample.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ var ZIndexExample = React.createClass({
flipped: false flipped: false
}; };
}, },

render() { render() {
const indices = this.state.flipped ? [-1, 0, 1, 2] : [2, 1, 0, -1]; const indices = this.state.flipped ? [-1, 0, 1, 2] : [2, 1, 0, -1];
return ( return (
Expand Down Expand Up @@ -128,7 +128,7 @@ var ZIndexExample = React.createClass({
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
); );
}, },

_handlePress() { _handlePress() {
this.setState({flipped: !this.state.flipped}); this.setState({flipped: !this.state.flipped});
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.graphics.Color; import android.graphics.Color;
import android.os.Build; import android.os.Build;
import android.view.View; import android.view.View;
import android.view.ViewGroup;


import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMap;
Expand All @@ -21,6 +22,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
private static final String PROP_TRANSFORM = "transform"; private static final String PROP_TRANSFORM = "transform";
private static final String PROP_OPACITY = "opacity"; private static final String PROP_OPACITY = "opacity";
private static final String PROP_ELEVATION = "elevation"; private static final String PROP_ELEVATION = "elevation";
private static final String PROP_Z_INDEX = "zIndex";
private static final String PROP_RENDER_TO_HARDWARE_TEXTURE = "renderToHardwareTextureAndroid"; private static final String PROP_RENDER_TO_HARDWARE_TEXTURE = "renderToHardwareTextureAndroid";
private static final String PROP_ACCESSIBILITY_LABEL = "accessibilityLabel"; private static final String PROP_ACCESSIBILITY_LABEL = "accessibilityLabel";
private static final String PROP_ACCESSIBILITY_COMPONENT_TYPE = "accessibilityComponentType"; private static final String PROP_ACCESSIBILITY_COMPONENT_TYPE = "accessibilityComponentType";
Expand Down Expand Up @@ -70,6 +72,12 @@ public void setElevation(T view, float elevation) {
// Do nothing on API < 21 // Do nothing on API < 21
} }


@ReactProp(name = PROP_Z_INDEX)
public void setZIndex(T view, float zIndex) {
int integerZIndex = Math.round(zIndex);
ViewGroupManager.setViewZIndex(view, integerZIndex);
}

@ReactProp(name = PROP_RENDER_TO_HARDWARE_TEXTURE) @ReactProp(name = PROP_RENDER_TO_HARDWARE_TEXTURE)
public void setRenderToHardwareTexture(T view, boolean useHWTexture) { public void setRenderToHardwareTexture(T view, boolean useHWTexture) {
view.setLayerType(useHWTexture ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null); view.setLayerType(useHWTexture ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;


import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.WeakHashMap;

/** /**
* Class providing children management API for view managers of classes extending ViewGroup. * Class providing children management API for view managers of classes extending ViewGroup.
*/ */
public abstract class ViewGroupManager <T extends ViewGroup> public abstract class ViewGroupManager <T extends ViewGroup>
extends BaseViewManager<T, LayoutShadowNode> { extends BaseViewManager<T, LayoutShadowNode> {


public static WeakHashMap<View, Integer> mZIndexHash = new WeakHashMap<>();

@Override @Override
public LayoutShadowNode createShadowNodeInstance() { public LayoutShadowNode createShadowNodeInstance() {
return new LayoutShadowNode(); return new LayoutShadowNode();
Expand All @@ -34,6 +42,59 @@ public void updateExtraData(T root, Object extraData) {


public void addView(T parent, View child, int index) { public void addView(T parent, View child, int index) {
parent.addView(child, index); parent.addView(child, index);
reorderChildrenByZIndex(parent);
}

public static void setViewZIndex(View view, int zIndex) {
mZIndexHash.put(view, zIndex);
// zIndex prop gets set BEFORE the view is added, so parent may be null.
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
reorderChildrenByZIndex(parent);
}
}

public static void reorderChildrenByZIndex(ViewGroup view) {
// Optimization: loop through the zIndexHash to test if there are any non-zero zIndexes
// If there aren't any, we can just return out
Collection<Integer> zIndexes = mZIndexHash.values();
boolean containsZIndexedElement = false;
for (Integer zIndex : zIndexes) {
if (zIndex != 0) {
containsZIndexedElement = true;
break;
}
}
if (!containsZIndexedElement) {
return;
}

// Add all children to a sortable ArrayList
ArrayList<View> viewsToSort = new ArrayList<>();
for (int i = 0; i < view.getChildCount(); i++) {
viewsToSort.add(view.getChildAt(i));
}
// Sort the views by zIndex
Collections.sort(viewsToSort, new Comparator<View>() {
@Override
public int compare(View view1, View view2) {
Integer view1ZIndex = mZIndexHash.get(view1);
if (view1ZIndex == null) {
view1ZIndex = 0;
}

Integer view2ZIndex = mZIndexHash.get(view2);
if (view2ZIndex == null) {
view2ZIndex = 0;
}
return view1ZIndex - view2ZIndex;
}
});
// Call .bringToFront on the sorted list of views
for (int i = 0; i < viewsToSort.size(); i++) {
viewsToSort.get(i).bringToFront();
}
view.invalidate();
} }


public int getChildCount(T parent) { public int getChildCount(T parent) {
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ public void addView(ReactViewGroup parent, View child, int index) {
} else { } else {
parent.addView(child, index); parent.addView(child, index);
} }
reorderChildrenByZIndex(parent);
} }


@Override @Override
Expand Down

1 comment on commit 3d3b067

@danpliego
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

Please sign in to comment.