/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.react.views.drawer; import javax.annotation.Nullable; import java.util.Map; import android.os.SystemClock; import android.support.v4.widget.DrawerLayout; import android.view.Gravity; import android.view.View; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ReactProp; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.views.drawer.events.DrawerClosedEvent; import com.facebook.react.views.drawer.events.DrawerOpenedEvent; import com.facebook.react.views.drawer.events.DrawerSlideEvent; import com.facebook.react.views.drawer.events.DrawerStateChangedEvent; /** * View Manager for {@link ReactDrawerLayout} components. */ public class ReactDrawerLayoutManager extends ViewGroupManager<ReactDrawerLayout> { private static final String REACT_CLASS = "AndroidDrawerLayout"; public static final int OPEN_DRAWER = 1; public static final int CLOSE_DRAWER = 2; @Override public String getName() { return REACT_CLASS; } @Override protected void addEventEmitters(ThemedReactContext reactContext, ReactDrawerLayout view) { view.setDrawerListener( new DrawerEventEmitter( view, reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher())); } @Override protected ReactDrawerLayout createViewInstance(ThemedReactContext context) { return new ReactDrawerLayout(context); } @ReactProp(name = "drawerPosition", defaultInt = Gravity.START) public void setDrawerPosition(ReactDrawerLayout view, int drawerPosition) { if (Gravity.START == drawerPosition || Gravity.END == drawerPosition) { view.setDrawerPosition(drawerPosition); } else { throw new JSApplicationIllegalArgumentException("Unknown drawerPosition " + drawerPosition); } } @ReactProp(name = "drawerWidth", defaultFloat = Float.NaN) public void getDrawerWidth(ReactDrawerLayout view, float width) { int widthInPx = Float.isNaN(width) ? ReactDrawerLayout.DEFAULT_DRAWER_WIDTH : Math.round(PixelUtil.toPixelFromDIP(width)); view.setDrawerWidth(widthInPx); } @Override public boolean needsCustomLayoutForChildren() { // Return true, since DrawerLayout will lay out it's own children. return true; } @Override public @Nullable Map<String, Integer> getCommandsMap() { return MapBuilder.of("openDrawer", OPEN_DRAWER, "closeDrawer", CLOSE_DRAWER); } @Override public void receiveCommand( ReactDrawerLayout root, int commandId, @Nullable ReadableArray args) { switch (commandId) { case OPEN_DRAWER: root.openDrawer(); break; case CLOSE_DRAWER: root.closeDrawer(); break; } } @Override public @Nullable Map getExportedViewConstants() { return MapBuilder.of( "DrawerPosition", MapBuilder.of("Left", Gravity.START, "Right", Gravity.END)); } @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { return MapBuilder.of( DrawerSlideEvent.EVENT_NAME, MapBuilder.of("registrationName", "onDrawerSlide"), DrawerOpenedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onDrawerOpen"), DrawerClosedEvent.EVENT_NAME, MapBuilder.of("registrationName", "onDrawerClose"), DrawerStateChangedEvent.EVENT_NAME, MapBuilder.of( "registrationName", "onDrawerStateChanged")); } /** * This method is overridden because of two reasons: * 1. A drawer must have exactly two children * 2. The second child that is added, is the navigationView, which gets panned from the side. */ @Override public void addView(ReactDrawerLayout parent, View child, int index) { if (getChildCount(parent) >= 2) { throw new JSApplicationIllegalArgumentException("The Drawer cannot have more than two children"); } if (index != 0 && index != 1) { throw new JSApplicationIllegalArgumentException( "The only valid indices for drawer's child are 0 or 1. Got " + index + " instead."); } parent.addView(child, index); parent.setDrawerProperties(); } public static class DrawerEventEmitter implements DrawerLayout.DrawerListener { private final DrawerLayout mDrawerLayout; private final EventDispatcher mEventDispatcher; public DrawerEventEmitter(DrawerLayout drawerLayout, EventDispatcher eventDispatcher) { mDrawerLayout = drawerLayout; mEventDispatcher = eventDispatcher; } @Override public void onDrawerSlide(View view, float v) { mEventDispatcher.dispatchEvent( new DrawerSlideEvent(mDrawerLayout.getId(), SystemClock.uptimeMillis(), v)); } @Override public void onDrawerOpened(View view) { mEventDispatcher.dispatchEvent( new DrawerOpenedEvent(mDrawerLayout.getId(), SystemClock.uptimeMillis())); } @Override public void onDrawerClosed(View view) { mEventDispatcher.dispatchEvent( new DrawerClosedEvent(mDrawerLayout.getId(), SystemClock.uptimeMillis())); } @Override public void onDrawerStateChanged(int i) { mEventDispatcher.dispatchEvent( new DrawerStateChangedEvent(mDrawerLayout.getId(), SystemClock.uptimeMillis(), i)); } } }