mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Move ToolbarAndroid Java code to FB internal
Summary: This moves the Toolbar Java files out RN and into our internal React shell. Reviewed By: fkgozali Differential Revision: D15469205 fbshipit-source-id: 15298505d74260618eb89673deb12d1b837b559f
This commit is contained in:
committed by
Facebook Github Bot
parent
56751851df
commit
cbbbb455dd
@@ -63,7 +63,6 @@ rn_android_library(
|
||||
react_native_target("java/com/facebook/react/views/text:text"),
|
||||
react_native_target("java/com/facebook/react/views/text/frescosupport:frescosupport"),
|
||||
react_native_target("java/com/facebook/react/views/textinput:textinput"),
|
||||
react_native_target("java/com/facebook/react/views/toolbar:toolbar"),
|
||||
react_native_target("java/com/facebook/react/views/view:view"),
|
||||
react_native_target("java/com/facebook/react/views/viewpager:viewpager"),
|
||||
react_native_target("java/com/facebook/react/module/annotations:annotations"),
|
||||
|
||||
@@ -59,7 +59,6 @@ import com.facebook.react.views.text.ReactTextViewManager;
|
||||
import com.facebook.react.views.text.ReactVirtualTextViewManager;
|
||||
import com.facebook.react.views.text.frescosupport.FrescoBasedReactTextInlineImageViewManager;
|
||||
import com.facebook.react.views.textinput.ReactTextInputManager;
|
||||
import com.facebook.react.views.toolbar.ReactToolbarManager;
|
||||
import com.facebook.react.views.view.ReactViewManager;
|
||||
import com.facebook.react.views.viewpager.ReactViewPagerManager;
|
||||
import java.util.ArrayList;
|
||||
@@ -335,7 +334,6 @@ public class MainReactPackage extends LazyReactPackage {
|
||||
viewManagers.add(new ReactScrollViewManager());
|
||||
viewManagers.add(new ReactSliderManager());
|
||||
viewManagers.add(new ReactSwitchManager());
|
||||
viewManagers.add(new ReactToolbarManager());
|
||||
viewManagers.add(new SwipeRefreshLayoutManager());
|
||||
|
||||
// Native equivalents
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
load("//tools/build_defs/oss:rn_defs.bzl", "YOGA_TARGET", "react_native_dep", "react_native_target", "rn_android_library")
|
||||
|
||||
rn_android_library(
|
||||
name = "toolbar",
|
||||
srcs = glob(["**/*.java"]),
|
||||
is_androidx = True,
|
||||
provided_deps = [
|
||||
react_native_dep("third-party/android/androidx:annotation"),
|
||||
react_native_dep("third-party/android/androidx:appcompat"),
|
||||
react_native_dep("third-party/android/androidx:core"),
|
||||
react_native_dep("third-party/android/androidx:fragment"),
|
||||
react_native_dep("third-party/android/androidx:legacy-support-core-ui"),
|
||||
react_native_dep("third-party/android/androidx:legacy-support-core-utils"),
|
||||
],
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
YOGA_TARGET,
|
||||
react_native_dep("libraries/fresco/fresco-react-native:fbcore"),
|
||||
react_native_dep("libraries/fresco/fresco-react-native:fresco-drawee"),
|
||||
react_native_dep("libraries/fresco/fresco-react-native:fresco-react-native"),
|
||||
react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"),
|
||||
react_native_dep("third-party/java/jsr-305:jsr-305"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/common:common"),
|
||||
react_native_target("java/com/facebook/react/uimanager:uimanager"),
|
||||
react_native_target("java/com/facebook/react/uimanager/annotations:annotations"),
|
||||
],
|
||||
)
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.toolbar;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import com.facebook.drawee.drawable.ForwardingDrawable;
|
||||
import com.facebook.imagepipeline.image.ImageInfo;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
|
||||
/**
|
||||
* Fresco currently sets drawables' intrinsic size to (-1, -1). This is to guarantee that scaling is
|
||||
* performed correctly. In the case of the Toolbar, we don't have access to the widget's internal
|
||||
* ImageView, which has width/height set to WRAP_CONTENT, which relies on intrinsic size.
|
||||
*
|
||||
* To work around this we have this class which just wraps another Drawable, but returns the correct
|
||||
* dimensions in getIntrinsicWidth/Height. This makes WRAP_CONTENT work in Toolbar's internals.
|
||||
*
|
||||
* This drawable uses the size of a loaded image to determine the intrinsic size. It therefore can't
|
||||
* be used safely until *after* an image has loaded, and must be replaced when the image is
|
||||
* replaced.
|
||||
*/
|
||||
public class DrawableWithIntrinsicSize extends ForwardingDrawable implements Drawable.Callback {
|
||||
|
||||
private final ImageInfo mImageInfo;
|
||||
|
||||
public DrawableWithIntrinsicSize(Drawable drawable, ImageInfo imageInfo) {
|
||||
super(drawable);
|
||||
mImageInfo = imageInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mImageInfo.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return mImageInfo.getHeight();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,332 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.toolbar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.drawee.controller.BaseControllerListener;
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchy;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.interfaces.DraweeController;
|
||||
import com.facebook.drawee.view.DraweeHolder;
|
||||
import com.facebook.drawee.view.MultiDraweeHolder;
|
||||
import com.facebook.imagepipeline.image.ImageInfo;
|
||||
import com.facebook.imagepipeline.image.QualityInfo;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Custom implementation of the {@link Toolbar} widget that adds support for remote images in logo
|
||||
* and navigationIcon using fresco.
|
||||
*/
|
||||
public class ReactToolbar extends Toolbar {
|
||||
|
||||
private static final String PROP_ACTION_ICON = "icon";
|
||||
private static final String PROP_ACTION_SHOW = "show";
|
||||
private static final String PROP_ACTION_SHOW_WITH_TEXT = "showWithText";
|
||||
private static final String PROP_ACTION_TITLE = "title";
|
||||
|
||||
private static final String PROP_ICON_URI = "uri";
|
||||
private static final String PROP_ICON_WIDTH = "width";
|
||||
private static final String PROP_ICON_HEIGHT = "height";
|
||||
|
||||
private final DraweeHolder mLogoHolder;
|
||||
private final DraweeHolder mNavIconHolder;
|
||||
private final DraweeHolder mOverflowIconHolder;
|
||||
private final MultiDraweeHolder<GenericDraweeHierarchy> mActionsHolder =
|
||||
new MultiDraweeHolder<>();
|
||||
|
||||
private IconControllerListener mLogoControllerListener;
|
||||
private IconControllerListener mNavIconControllerListener;
|
||||
private IconControllerListener mOverflowIconControllerListener;
|
||||
|
||||
/**
|
||||
* Attaches specific icon width & height to a BaseControllerListener which will be used to
|
||||
* create the Drawable
|
||||
*/
|
||||
private abstract class IconControllerListener extends BaseControllerListener<ImageInfo> {
|
||||
|
||||
private final DraweeHolder mHolder;
|
||||
|
||||
private IconImageInfo mIconImageInfo;
|
||||
|
||||
public IconControllerListener(DraweeHolder holder) {
|
||||
mHolder = holder;
|
||||
}
|
||||
|
||||
public void setIconImageInfo(IconImageInfo iconImageInfo) {
|
||||
mIconImageInfo = iconImageInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinalImageSet(String id, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) {
|
||||
super.onFinalImageSet(id, imageInfo, animatable);
|
||||
|
||||
final ImageInfo info = mIconImageInfo != null ? mIconImageInfo : imageInfo;
|
||||
setDrawable(new DrawableWithIntrinsicSize(mHolder.getTopLevelDrawable(), info));
|
||||
}
|
||||
|
||||
protected abstract void setDrawable(Drawable d);
|
||||
|
||||
}
|
||||
|
||||
private class ActionIconControllerListener extends IconControllerListener {
|
||||
private final MenuItem mItem;
|
||||
|
||||
ActionIconControllerListener(MenuItem item, DraweeHolder holder) {
|
||||
super(holder);
|
||||
mItem = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDrawable(Drawable d) {
|
||||
mItem.setIcon(d);
|
||||
ReactToolbar.this.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple implementation of ImageInfo, only providing width & height
|
||||
*/
|
||||
private static class IconImageInfo implements ImageInfo {
|
||||
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
public IconImageInfo(int width, int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QualityInfo getQualityInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ReactToolbar(Context context) {
|
||||
super(context);
|
||||
|
||||
mLogoHolder = DraweeHolder.create(createDraweeHierarchy(), context);
|
||||
mNavIconHolder = DraweeHolder.create(createDraweeHierarchy(), context);
|
||||
mOverflowIconHolder = DraweeHolder.create(createDraweeHierarchy(), context);
|
||||
|
||||
mLogoControllerListener = new IconControllerListener(mLogoHolder) {
|
||||
@Override
|
||||
protected void setDrawable(Drawable d) {
|
||||
setLogo(d);
|
||||
}
|
||||
};
|
||||
|
||||
mNavIconControllerListener = new IconControllerListener(mNavIconHolder) {
|
||||
@Override
|
||||
protected void setDrawable(Drawable d) {
|
||||
setNavigationIcon(d);
|
||||
}
|
||||
};
|
||||
|
||||
mOverflowIconControllerListener = new IconControllerListener(mOverflowIconHolder) {
|
||||
@Override
|
||||
protected void setDrawable(Drawable d) {
|
||||
setOverflowIcon(d);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private final Runnable mLayoutRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
measure(
|
||||
MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.EXACTLY));
|
||||
layout(getLeft(), getTop(), getRight(), getBottom());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void requestLayout() {
|
||||
super.requestLayout();
|
||||
|
||||
// The toolbar relies on a measure + layout pass happening after it calls requestLayout().
|
||||
// Without this, certain calls (e.g. setLogo) only take effect after a second invalidation.
|
||||
post(mLayoutRunnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
detachDraweeHolders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTemporaryDetach() {
|
||||
super.onStartTemporaryDetach();
|
||||
detachDraweeHolders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
attachDraweeHolders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishTemporaryDetach() {
|
||||
super.onFinishTemporaryDetach();
|
||||
attachDraweeHolders();
|
||||
}
|
||||
|
||||
private void detachDraweeHolders() {
|
||||
mLogoHolder.onDetach();
|
||||
mNavIconHolder.onDetach();
|
||||
mOverflowIconHolder.onDetach();
|
||||
mActionsHolder.onDetach();
|
||||
}
|
||||
|
||||
private void attachDraweeHolders() {
|
||||
mLogoHolder.onAttach();
|
||||
mNavIconHolder.onAttach();
|
||||
mOverflowIconHolder.onAttach();
|
||||
mActionsHolder.onAttach();
|
||||
}
|
||||
|
||||
/* package */ void setLogoSource(@Nullable ReadableMap source) {
|
||||
setIconSource(source, mLogoControllerListener, mLogoHolder);
|
||||
}
|
||||
|
||||
/* package */ void setNavIconSource(@Nullable ReadableMap source) {
|
||||
setIconSource(source, mNavIconControllerListener, mNavIconHolder);
|
||||
}
|
||||
|
||||
/* package */ void setOverflowIconSource(@Nullable ReadableMap source) {
|
||||
setIconSource(source, mOverflowIconControllerListener, mOverflowIconHolder);
|
||||
}
|
||||
|
||||
/* package */ void setActions(@Nullable ReadableArray actions) {
|
||||
Menu menu = getMenu();
|
||||
menu.clear();
|
||||
mActionsHolder.clear();
|
||||
if (actions != null) {
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
ReadableMap action = actions.getMap(i);
|
||||
|
||||
MenuItem item = menu.add(Menu.NONE, Menu.NONE, i, action.getString(PROP_ACTION_TITLE));
|
||||
|
||||
if (action.hasKey(PROP_ACTION_ICON)) {
|
||||
setMenuItemIcon(item, action.getMap(PROP_ACTION_ICON));
|
||||
}
|
||||
|
||||
int showAsAction = action.hasKey(PROP_ACTION_SHOW)
|
||||
? action.getInt(PROP_ACTION_SHOW)
|
||||
: MenuItem.SHOW_AS_ACTION_NEVER;
|
||||
if (action.hasKey(PROP_ACTION_SHOW_WITH_TEXT) &&
|
||||
action.getBoolean(PROP_ACTION_SHOW_WITH_TEXT)) {
|
||||
showAsAction = showAsAction | MenuItem.SHOW_AS_ACTION_WITH_TEXT;
|
||||
}
|
||||
item.setShowAsAction(showAsAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setMenuItemIcon(final MenuItem item, ReadableMap iconSource) {
|
||||
|
||||
DraweeHolder<GenericDraweeHierarchy> holder =
|
||||
DraweeHolder.create(createDraweeHierarchy(), getContext());
|
||||
ActionIconControllerListener controllerListener = new ActionIconControllerListener(item, holder);
|
||||
controllerListener.setIconImageInfo(getIconImageInfo(iconSource));
|
||||
|
||||
setIconSource(iconSource, controllerListener, holder);
|
||||
|
||||
mActionsHolder.add(holder);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an icon for a specific icon source. If the uri indicates an icon
|
||||
* to be somewhere remote (http/https) or on the local filesystem, it uses fresco to load it.
|
||||
* Otherwise it loads the Drawable from the Resources and directly returns it via a callback
|
||||
*/
|
||||
private void setIconSource(ReadableMap source, IconControllerListener controllerListener, DraweeHolder holder) {
|
||||
|
||||
String uri = source != null ? source.getString(PROP_ICON_URI) : null;
|
||||
|
||||
if (uri == null) {
|
||||
controllerListener.setIconImageInfo(null);
|
||||
controllerListener.setDrawable(null);
|
||||
} else if (uri.startsWith("http://") || uri.startsWith("https://") || uri.startsWith("file://")) {
|
||||
controllerListener.setIconImageInfo(getIconImageInfo(source));
|
||||
DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||
.setUri(Uri.parse(uri))
|
||||
.setControllerListener(controllerListener)
|
||||
.setOldController(holder.getController())
|
||||
.build();
|
||||
holder.setController(controller);
|
||||
holder.getTopLevelDrawable().setVisible(true, true);
|
||||
} else {
|
||||
controllerListener.setDrawable(getDrawableByName(uri));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private GenericDraweeHierarchy createDraweeHierarchy() {
|
||||
return new GenericDraweeHierarchyBuilder(getResources())
|
||||
.setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
|
||||
.setFadeDuration(0)
|
||||
.build();
|
||||
}
|
||||
|
||||
private int getDrawableResourceByName(String name) {
|
||||
return getResources().getIdentifier(
|
||||
name,
|
||||
"drawable",
|
||||
getContext().getPackageName());
|
||||
}
|
||||
|
||||
private Drawable getDrawableByName(String name) {
|
||||
int drawableResId = getDrawableResourceByName(name);
|
||||
if (drawableResId != 0) {
|
||||
return getResources().getDrawable(getDrawableResourceByName(name));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private IconImageInfo getIconImageInfo(ReadableMap source) {
|
||||
if (source.hasKey(PROP_ICON_WIDTH) && source.hasKey(PROP_ICON_HEIGHT)) {
|
||||
final int width = Math.round(PixelUtil.toPixelFromDIP(source.getInt(PROP_ICON_WIDTH)));
|
||||
final int height = Math.round(PixelUtil.toPixelFromDIP(source.getInt(PROP_ICON_HEIGHT)));
|
||||
return new IconImageInfo(width, height);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.toolbar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import android.util.LayoutDirection;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.views.toolbar.events.ToolbarClickEvent;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Manages instances of ReactToolbar.
|
||||
*/
|
||||
public class ReactToolbarManager extends ViewGroupManager<ReactToolbar> {
|
||||
|
||||
private static final String REACT_CLASS = "ToolbarAndroid";
|
||||
private static final int COMMAND_DISMISS_POPUP_MENUS = 1;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REACT_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReactToolbar createViewInstance(ThemedReactContext reactContext) {
|
||||
return new ReactToolbar(reactContext);
|
||||
}
|
||||
|
||||
@ReactProp(name = "logo")
|
||||
public void setLogo(ReactToolbar view, @Nullable ReadableMap logo) {
|
||||
view.setLogoSource(logo);
|
||||
}
|
||||
|
||||
@ReactProp(name = "navIcon")
|
||||
public void setNavIcon(ReactToolbar view, @Nullable ReadableMap navIcon) {
|
||||
view.setNavIconSource(navIcon);
|
||||
}
|
||||
|
||||
@ReactProp(name = "overflowIcon")
|
||||
public void setOverflowIcon(ReactToolbar view, @Nullable ReadableMap overflowIcon) {
|
||||
view.setOverflowIconSource(overflowIcon);
|
||||
}
|
||||
|
||||
@ReactProp(name = "rtl")
|
||||
public void setRtl(ReactToolbar view, boolean rtl) {
|
||||
ViewCompat.setLayoutDirection(view, rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR);
|
||||
}
|
||||
|
||||
@ReactProp(name = "subtitle")
|
||||
public void setSubtitle(ReactToolbar view, @Nullable String subtitle) {
|
||||
view.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@ReactProp(name = "subtitleColor", customType = "Color")
|
||||
public void setSubtitleColor(ReactToolbar view, @Nullable Integer subtitleColor) {
|
||||
int[] defaultColors = getDefaultColors(view.getContext());
|
||||
if (subtitleColor != null) {
|
||||
view.setSubtitleTextColor(subtitleColor);
|
||||
} else {
|
||||
view.setSubtitleTextColor(defaultColors[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "title")
|
||||
public void setTitle(ReactToolbar view, @Nullable String title) {
|
||||
view.setTitle(title);
|
||||
}
|
||||
|
||||
@ReactProp(name = "titleColor", customType = "Color")
|
||||
public void setTitleColor(ReactToolbar view, @Nullable Integer titleColor) {
|
||||
int[] defaultColors = getDefaultColors(view.getContext());
|
||||
if (titleColor != null) {
|
||||
view.setTitleTextColor(titleColor);
|
||||
} else {
|
||||
view.setTitleTextColor(defaultColors[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "contentInsetStart", defaultFloat = Float.NaN)
|
||||
public void setContentInsetStart(ReactToolbar view, float insetStart) {
|
||||
int inset = Float.isNaN(insetStart) ?
|
||||
getDefaultContentInsets(view.getContext())[0] :
|
||||
Math.round(PixelUtil.toPixelFromDIP(insetStart));
|
||||
view.setContentInsetsRelative(inset, view.getContentInsetEnd());
|
||||
}
|
||||
|
||||
@ReactProp(name = "contentInsetEnd", defaultFloat = Float.NaN)
|
||||
public void setContentInsetEnd(ReactToolbar view, float insetEnd) {
|
||||
int inset = Float.isNaN(insetEnd) ?
|
||||
getDefaultContentInsets(view.getContext())[1] :
|
||||
Math.round(PixelUtil.toPixelFromDIP(insetEnd));
|
||||
view.setContentInsetsRelative(view.getContentInsetStart(), inset);
|
||||
}
|
||||
|
||||
@ReactProp(name = "nativeActions")
|
||||
public void setActions(ReactToolbar view, @Nullable ReadableArray actions) {
|
||||
view.setActions(actions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addEventEmitters(final ThemedReactContext reactContext, final ReactToolbar view) {
|
||||
final EventDispatcher mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
|
||||
view.setNavigationOnClickListener(
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mEventDispatcher.dispatchEvent(
|
||||
new ToolbarClickEvent(view.getId(), -1));
|
||||
}
|
||||
});
|
||||
|
||||
view.setOnMenuItemClickListener(
|
||||
new ReactToolbar.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
mEventDispatcher.dispatchEvent(
|
||||
new ToolbarClickEvent(
|
||||
view.getId(),
|
||||
menuItem.getOrder()));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, Object> getExportedViewConstants() {
|
||||
return MapBuilder.<String, Object>of(
|
||||
"ShowAsAction",
|
||||
MapBuilder.of(
|
||||
"never", MenuItem.SHOW_AS_ACTION_NEVER,
|
||||
"always", MenuItem.SHOW_AS_ACTION_ALWAYS,
|
||||
"ifRoom", MenuItem.SHOW_AS_ACTION_IF_ROOM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsCustomLayoutForChildren() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Map<String, Integer> getCommandsMap() {
|
||||
return MapBuilder.of("dismissPopupMenus", COMMAND_DISMISS_POPUP_MENUS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveCommand(ReactToolbar view, int commandType, @Nullable ReadableArray args) {
|
||||
switch (commandType) {
|
||||
case COMMAND_DISMISS_POPUP_MENUS: {
|
||||
view.dismissPopupMenus();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unsupported command %d received by %s.",
|
||||
commandType,
|
||||
getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
private int[] getDefaultContentInsets(Context context) {
|
||||
Resources.Theme theme = context.getTheme();
|
||||
TypedArray toolbarStyle = null;
|
||||
TypedArray contentInsets = null;
|
||||
|
||||
try {
|
||||
toolbarStyle =
|
||||
theme.obtainStyledAttributes(new int[] {getIdentifier(context, "toolbarStyle")});
|
||||
|
||||
int toolbarStyleResId = toolbarStyle.getResourceId(0, 0);
|
||||
|
||||
contentInsets =
|
||||
theme.obtainStyledAttributes(
|
||||
toolbarStyleResId,
|
||||
new int[] {
|
||||
getIdentifier(context, "contentInsetStart"),
|
||||
getIdentifier(context, "contentInsetEnd"),
|
||||
});
|
||||
|
||||
int contentInsetStart = contentInsets.getDimensionPixelSize(0, 0);
|
||||
int contentInsetEnd = contentInsets.getDimensionPixelSize(1, 0);
|
||||
|
||||
return new int[] {contentInsetStart, contentInsetEnd};
|
||||
} finally {
|
||||
recycleQuietly(toolbarStyle);
|
||||
recycleQuietly(contentInsets);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static int[] getDefaultColors(Context context) {
|
||||
Resources.Theme theme = context.getTheme();
|
||||
TypedArray toolbarStyle = null;
|
||||
TypedArray textAppearances = null;
|
||||
TypedArray titleTextAppearance = null;
|
||||
TypedArray subtitleTextAppearance = null;
|
||||
|
||||
try {
|
||||
toolbarStyle =
|
||||
theme.obtainStyledAttributes(new int[] {getIdentifier(context, "toolbarStyle")});
|
||||
|
||||
int toolbarStyleResId = toolbarStyle.getResourceId(0, 0);
|
||||
textAppearances =
|
||||
theme.obtainStyledAttributes(
|
||||
toolbarStyleResId,
|
||||
new int[] {
|
||||
getIdentifier(context, "titleTextAppearance"),
|
||||
getIdentifier(context, "subtitleTextAppearance"),
|
||||
});
|
||||
|
||||
int titleTextAppearanceResId = textAppearances.getResourceId(0, 0);
|
||||
int subtitleTextAppearanceResId = textAppearances.getResourceId(1, 0);
|
||||
|
||||
titleTextAppearance = theme
|
||||
.obtainStyledAttributes(titleTextAppearanceResId, new int[]{android.R.attr.textColor});
|
||||
subtitleTextAppearance = theme
|
||||
.obtainStyledAttributes(subtitleTextAppearanceResId, new int[]{android.R.attr.textColor});
|
||||
|
||||
int titleTextColor = titleTextAppearance.getColor(0, Color.BLACK);
|
||||
int subtitleTextColor = subtitleTextAppearance.getColor(0, Color.BLACK);
|
||||
|
||||
return new int[] {titleTextColor, subtitleTextColor};
|
||||
} finally {
|
||||
recycleQuietly(toolbarStyle);
|
||||
recycleQuietly(textAppearances);
|
||||
recycleQuietly(titleTextAppearance);
|
||||
recycleQuietly(subtitleTextAppearance);
|
||||
}
|
||||
}
|
||||
|
||||
private static void recycleQuietly(@Nullable TypedArray style) {
|
||||
if (style != null) {
|
||||
style.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The appcompat-v7 BUCK dep is listed as a provided_dep, which complains that
|
||||
* com.facebook.react.R doesn't exist. Since the attributes provided from a parent, we can access
|
||||
* those attributes dynamically.
|
||||
*/
|
||||
private static int getIdentifier(Context context, String name) {
|
||||
return context.getResources().getIdentifier(name, "attr", context.getPackageName());
|
||||
}
|
||||
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
package com.facebook.react.views.toolbar.events;
|
||||
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.bridge.WritableNativeMap;
|
||||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
|
||||
/**
|
||||
* Represents a click on the toolbar.
|
||||
* Position is meaningful when the click happened on a menu
|
||||
*/
|
||||
public class ToolbarClickEvent extends Event<ToolbarClickEvent> {
|
||||
|
||||
private static final String EVENT_NAME = "topSelect";
|
||||
private final int position;
|
||||
|
||||
public ToolbarClickEvent(int viewId, int position) {
|
||||
super(viewId);
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventName() {
|
||||
return EVENT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCoalesce() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(RCTEventEmitter rctEventEmitter) {
|
||||
WritableMap event = new WritableNativeMap();
|
||||
event.putInt("position", getPosition());
|
||||
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user