Permalink
Browse files

Add zIndex support

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...
Tucker Connelly Facebook Github Bot 3
Tucker Connelly authored and Facebook Github Bot 3 committed Jun 29, 2016
1 parent 3085b35 commit 3d3b067f6fc831b6b23726087fe39cf39ef86f00
@@ -93,7 +93,7 @@ var ZIndexExample = React.createClass({
flipped: false
};
},
render() {
const indices = this.state.flipped ? [-1, 0, 1, 2] : [2, 1, 0, -1];
return (
@@ -128,7 +128,7 @@ var ZIndexExample = React.createClass({
</TouchableWithoutFeedback>
);
},
_handlePress() {
this.setState({flipped: !this.state.flipped});
}
@@ -5,6 +5,7 @@
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
@@ -21,6 +22,7 @@
private static final String PROP_TRANSFORM = "transform";
private static final String PROP_OPACITY = "opacity";
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_ACCESSIBILITY_LABEL = "accessibilityLabel";
private static final String PROP_ACCESSIBILITY_COMPONENT_TYPE = "accessibilityComponentType";
@@ -70,6 +72,12 @@ public void setElevation(T view, float elevation) {
// 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)
public void setRenderToHardwareTexture(T view, boolean useHWTexture) {
view.setLayerType(useHWTexture ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
@@ -12,12 +12,20 @@
import android.view.View;
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.
*/
public abstract class ViewGroupManager <T extends ViewGroup>
extends BaseViewManager<T, LayoutShadowNode> {
public static WeakHashMap<View, Integer> mZIndexHash = new WeakHashMap<>();
@Override
public LayoutShadowNode createShadowNodeInstance() {
return new LayoutShadowNode();
@@ -34,6 +42,59 @@ public void updateExtraData(T root, Object extraData) {
public void addView(T parent, View child, int 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) {
@@ -195,6 +195,7 @@ public void addView(ReactViewGroup parent, View child, int index) {
} else {
parent.addView(child, index);
}
reorderChildrenByZIndex(parent);
}
@Override

1 comment on commit 3d3b067

@danpliego

This comment has been minimized.

Show comment
Hide comment

thanks!

Please sign in to comment.