add remote image support to toolbar
Differential Revision: D2493627
This commit is contained in:
parent
ee3f7e9d21
commit
5ca5ec7688
|
@ -93,6 +93,14 @@ var ToolbarAndroidExample = React.createClass({
|
||||||
Touch the icon to reset the custom colors to the default (theme-provided) ones.
|
Touch the icon to reset the custom colors to the default (theme-provided) ones.
|
||||||
</Text>
|
</Text>
|
||||||
</UIExplorerBlock>
|
</UIExplorerBlock>
|
||||||
|
<UIExplorerBlock title="Toolbar with remote logo & navIcon">
|
||||||
|
<ToolbarAndroid
|
||||||
|
actions={[{title: 'Bunny', icon: require('./bunny.png'), show: 'always'}]}
|
||||||
|
logo={require('./hawk.png')}
|
||||||
|
navIcon={require('./bunny.png')}
|
||||||
|
title="Bunny and Hawk"
|
||||||
|
style={styles.toolbar} />
|
||||||
|
</UIExplorerBlock>
|
||||||
</UIExplorerPage>
|
</UIExplorerPage>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
|
@ -13,11 +13,13 @@
|
||||||
|
|
||||||
var Image = require('Image');
|
var Image = require('Image');
|
||||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||||
|
var RCTUIManager = require('NativeModules').UIManager;
|
||||||
var React = require('React');
|
var React = require('React');
|
||||||
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
||||||
var ReactPropTypes = require('ReactPropTypes');
|
var ReactPropTypes = require('ReactPropTypes');
|
||||||
|
|
||||||
var requireNativeComponent = require('requireNativeComponent');
|
var requireNativeComponent = require('requireNativeComponent');
|
||||||
|
var resolveAssetSource = require('resolveAssetSource');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* React component that wraps the Android-only [`Toolbar` widget][0]. A Toolbar can display a logo,
|
* React component that wraps the Android-only [`Toolbar` widget][0]. A Toolbar can display a logo,
|
||||||
|
@ -27,6 +29,12 @@ var requireNativeComponent = require('requireNativeComponent');
|
||||||
*
|
*
|
||||||
* If the toolbar has an only child, it will be displayed between the title and actions.
|
* If the toolbar has an only child, it will be displayed between the title and actions.
|
||||||
*
|
*
|
||||||
|
* Although the Toolbar supports remote images for the logo, navigation and action icons, this
|
||||||
|
* should only be used in DEV mode where `require('./some_icon.png')` translates into a packager
|
||||||
|
* URL. In release mode you should always use a drawable resource for these icons. Using
|
||||||
|
* `require('./some_icon.png')` will do this automatically for you, so as long as you don't
|
||||||
|
* explicitly use e.g. `{uri: 'http://...'}`, you will be good.
|
||||||
|
*
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
|
@ -115,16 +123,10 @@ var ToolbarAndroid = React.createClass({
|
||||||
...this.props,
|
...this.props,
|
||||||
};
|
};
|
||||||
if (this.props.logo) {
|
if (this.props.logo) {
|
||||||
if (!this.props.logo.isStatic) {
|
nativeProps.logo = resolveAssetSource(this.props.logo);
|
||||||
throw 'logo prop should be a static image (obtained via ix)';
|
|
||||||
}
|
|
||||||
nativeProps.logo = this.props.logo.uri;
|
|
||||||
}
|
}
|
||||||
if (this.props.navIcon) {
|
if (this.props.navIcon) {
|
||||||
if (!this.props.navIcon.isStatic) {
|
nativeProps.navIcon = resolveAssetSource(this.props.navIcon);
|
||||||
throw 'navIcon prop should be static image (obtained via ix)';
|
|
||||||
}
|
|
||||||
nativeProps.navIcon = this.props.navIcon.uri;
|
|
||||||
}
|
}
|
||||||
if (this.props.actions) {
|
if (this.props.actions) {
|
||||||
nativeProps.actions = [];
|
nativeProps.actions = [];
|
||||||
|
@ -133,10 +135,10 @@ var ToolbarAndroid = React.createClass({
|
||||||
...this.props.actions[i],
|
...this.props.actions[i],
|
||||||
};
|
};
|
||||||
if (action.icon) {
|
if (action.icon) {
|
||||||
if (!action.icon.isStatic) {
|
action.icon = resolveAssetSource(action.icon);
|
||||||
throw 'action icons should be static images (obtained via ix)';
|
|
||||||
}
|
}
|
||||||
action.icon = action.icon.uri;
|
if (action.show) {
|
||||||
|
action.show = RCTUIManager.ToolbarAndroid.Constants.ShowAsAction[action.show];
|
||||||
}
|
}
|
||||||
nativeProps.actions.push(action);
|
nativeProps.actions.push(action);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
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 (int) PixelUtil.toDIPFromPixel(mImageInfo.getWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIntrinsicHeight() {
|
||||||
|
return (int) PixelUtil.toDIPFromPixel(mImageInfo.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,250 @@
|
||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.react.views.toolbar;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Animatable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.v7.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.controller.ControllerListener;
|
||||||
|
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.react.bridge.ReadableArray;
|
||||||
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 final DraweeHolder mLogoHolder;
|
||||||
|
private final DraweeHolder mNavIconHolder;
|
||||||
|
private final MultiDraweeHolder<GenericDraweeHierarchy> mActionsHolder =
|
||||||
|
new MultiDraweeHolder<>();
|
||||||
|
|
||||||
|
private final ControllerListener<ImageInfo> mLogoControllerListener =
|
||||||
|
new BaseControllerListener<ImageInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onFinalImageSet(
|
||||||
|
String id,
|
||||||
|
@Nullable final ImageInfo imageInfo,
|
||||||
|
@Nullable Animatable animatable) {
|
||||||
|
if (imageInfo != null) {
|
||||||
|
final DrawableWithIntrinsicSize logoDrawable =
|
||||||
|
new DrawableWithIntrinsicSize(mLogoHolder.getTopLevelDrawable(), imageInfo);
|
||||||
|
setLogo(logoDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final ControllerListener<ImageInfo> mNavIconControllerListener =
|
||||||
|
new BaseControllerListener<ImageInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onFinalImageSet(
|
||||||
|
String id,
|
||||||
|
@Nullable final ImageInfo imageInfo,
|
||||||
|
@Nullable Animatable animatable) {
|
||||||
|
if (imageInfo != null) {
|
||||||
|
final DrawableWithIntrinsicSize navIconDrawable =
|
||||||
|
new DrawableWithIntrinsicSize(mNavIconHolder.getTopLevelDrawable(), imageInfo);
|
||||||
|
setNavigationIcon(navIconDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static class ActionIconControllerListener extends BaseControllerListener<ImageInfo> {
|
||||||
|
private final MenuItem mItem;
|
||||||
|
private final DraweeHolder mHolder;
|
||||||
|
|
||||||
|
ActionIconControllerListener(MenuItem item, DraweeHolder holder) {
|
||||||
|
mItem = item;
|
||||||
|
mHolder = holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinalImageSet(
|
||||||
|
String id,
|
||||||
|
@Nullable ImageInfo imageInfo,
|
||||||
|
@Nullable Animatable animatable) {
|
||||||
|
if (imageInfo != null) {
|
||||||
|
mItem.setIcon(new DrawableWithIntrinsicSize(mHolder.getTopLevelDrawable(), imageInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReactToolbar(Context context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
mLogoHolder = DraweeHolder.create(createDraweeHierarchy(), context);
|
||||||
|
mNavIconHolder = DraweeHolder.create(createDraweeHierarchy(), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
mLogoHolder.onAttach();
|
||||||
|
mNavIconHolder.onAttach();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void detachDraweeHolders() {
|
||||||
|
mLogoHolder.onDetach();
|
||||||
|
mNavIconHolder.onDetach();
|
||||||
|
mActionsHolder.onDetach();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attachDraweeHolders() {
|
||||||
|
mLogoHolder.onAttach();
|
||||||
|
mNavIconHolder.onAttach();
|
||||||
|
mActionsHolder.onAttach();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ void setLogoSource(@Nullable ReadableMap source) {
|
||||||
|
String uri = source != null ? source.getString("uri") : null;
|
||||||
|
if (uri == null) {
|
||||||
|
setLogo(null);
|
||||||
|
} else if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
||||||
|
DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||||
|
.setUri(Uri.parse(uri))
|
||||||
|
.setControllerListener(mLogoControllerListener)
|
||||||
|
.setOldController(mLogoHolder.getController())
|
||||||
|
.build();
|
||||||
|
mLogoHolder.setController(controller);
|
||||||
|
} else {
|
||||||
|
setLogo(getDrawableResourceByName(uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ void setNavIconSource(@Nullable ReadableMap source) {
|
||||||
|
String uri = source != null ? source.getString("uri") : null;
|
||||||
|
if (uri == null) {
|
||||||
|
setNavigationIcon(null);
|
||||||
|
} else if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
||||||
|
DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||||
|
.setUri(Uri.parse(uri))
|
||||||
|
.setControllerListener(mNavIconControllerListener)
|
||||||
|
.setOldController(mNavIconHolder.getController())
|
||||||
|
.build();
|
||||||
|
mNavIconHolder.setController(controller);
|
||||||
|
} else {
|
||||||
|
setNavigationIcon(getDrawableResourceByName(uri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
ReadableMap icon = action.hasKey(PROP_ACTION_ICON) ? action.getMap(PROP_ACTION_ICON) : null;
|
||||||
|
if (icon != null) {
|
||||||
|
String iconSource = icon.getString("uri");
|
||||||
|
if (iconSource.startsWith("http://") || iconSource.startsWith("https://")) {
|
||||||
|
setMenuItemIcon(item, icon);
|
||||||
|
} else {
|
||||||
|
item.setIcon(getDrawableResourceByName(iconSource));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is only used when the icon is remote (http/s). Creates & adds a new {@link DraweeHolder}
|
||||||
|
* to {@link #mActionsHolder} and attaches a {@link ActionIconControllerListener} that just sets
|
||||||
|
* the top level drawable when it's loaded.
|
||||||
|
*/
|
||||||
|
private void setMenuItemIcon(MenuItem item, ReadableMap icon) {
|
||||||
|
String iconSource = icon.getString("uri");
|
||||||
|
|
||||||
|
DraweeHolder<GenericDraweeHierarchy> holder =
|
||||||
|
DraweeHolder.create(createDraweeHierarchy(), getContext());
|
||||||
|
DraweeController controller = Fresco.newDraweeControllerBuilder()
|
||||||
|
.setUri(Uri.parse(iconSource))
|
||||||
|
.setControllerListener(new ActionIconControllerListener(item, holder))
|
||||||
|
.setOldController(holder.getController())
|
||||||
|
.build();
|
||||||
|
holder.setController(controller);
|
||||||
|
|
||||||
|
mActionsHolder.add(holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -11,19 +11,20 @@ package com.facebook.react.views.toolbar;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.facebook.react.R;
|
import com.facebook.react.R;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
|
import com.facebook.react.common.MapBuilder;
|
||||||
import com.facebook.react.uimanager.ReactProp;
|
import com.facebook.react.uimanager.ReactProp;
|
||||||
import com.facebook.react.uimanager.ThemedReactContext;
|
import com.facebook.react.uimanager.ThemedReactContext;
|
||||||
import com.facebook.react.uimanager.UIManagerModule;
|
import com.facebook.react.uimanager.UIManagerModule;
|
||||||
|
@ -32,52 +33,39 @@ import com.facebook.react.uimanager.events.EventDispatcher;
|
||||||
import com.facebook.react.views.toolbar.events.ToolbarClickEvent;
|
import com.facebook.react.views.toolbar.events.ToolbarClickEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages instances of Toolbar.
|
* Manages instances of ReactToolbar.
|
||||||
*/
|
*/
|
||||||
public class ReactToolbarManager extends ViewGroupManager<Toolbar> {
|
public class ReactToolbarManager extends ViewGroupManager<ReactToolbar> {
|
||||||
|
|
||||||
private static final String REACT_CLASS = "ToolbarAndroid";
|
private static final String REACT_CLASS = "ToolbarAndroid";
|
||||||
|
|
||||||
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";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return REACT_CLASS;
|
return REACT_CLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Toolbar createViewInstance(ThemedReactContext reactContext) {
|
protected ReactToolbar createViewInstance(ThemedReactContext reactContext) {
|
||||||
return new Toolbar(reactContext);
|
return new ReactToolbar(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "logo")
|
@ReactProp(name = "logo")
|
||||||
public void setLogo(Toolbar view, @Nullable String logo) {
|
public void setLogo(ReactToolbar view, @Nullable ReadableMap logo) {
|
||||||
if (logo != null) {
|
view.setLogoSource(logo);
|
||||||
view.setLogo(getDrawableResourceByName(view.getContext(), logo));
|
|
||||||
} else {
|
|
||||||
view.setLogo(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "navIcon")
|
@ReactProp(name = "navIcon")
|
||||||
public void setNavIcon(Toolbar view, @Nullable String navIcon) {
|
public void setNavIcon(ReactToolbar view, @Nullable ReadableMap navIcon) {
|
||||||
if (navIcon != null) {
|
view.setNavIconSource(navIcon);
|
||||||
view.setNavigationIcon(getDrawableResourceByName(view.getContext(), navIcon));
|
|
||||||
} else {
|
|
||||||
view.setNavigationIcon(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "subtitle")
|
@ReactProp(name = "subtitle")
|
||||||
public void setSubtitle(Toolbar view, @Nullable String subtitle) {
|
public void setSubtitle(ReactToolbar view, @Nullable String subtitle) {
|
||||||
view.setSubtitle(subtitle);
|
view.setSubtitle(subtitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "subtitleColor", customType = "Color")
|
@ReactProp(name = "subtitleColor", customType = "Color")
|
||||||
public void setSubtitleColor(Toolbar view, @Nullable Integer subtitleColor) {
|
public void setSubtitleColor(ReactToolbar view, @Nullable Integer subtitleColor) {
|
||||||
int[] defaultColors = getDefaultColors(view.getContext());
|
int[] defaultColors = getDefaultColors(view.getContext());
|
||||||
if (subtitleColor != null) {
|
if (subtitleColor != null) {
|
||||||
view.setSubtitleTextColor(subtitleColor);
|
view.setSubtitleTextColor(subtitleColor);
|
||||||
|
@ -87,12 +75,12 @@ public class ReactToolbarManager extends ViewGroupManager<Toolbar> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "title")
|
@ReactProp(name = "title")
|
||||||
public void setTitle(Toolbar view, @Nullable String title) {
|
public void setTitle(ReactToolbar view, @Nullable String title) {
|
||||||
view.setTitle(title);
|
view.setTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "titleColor", customType = "Color")
|
@ReactProp(name = "titleColor", customType = "Color")
|
||||||
public void setTitleColor(Toolbar view, @Nullable Integer titleColor) {
|
public void setTitleColor(ReactToolbar view, @Nullable Integer titleColor) {
|
||||||
int[] defaultColors = getDefaultColors(view.getContext());
|
int[] defaultColors = getDefaultColors(view.getContext());
|
||||||
if (titleColor != null) {
|
if (titleColor != null) {
|
||||||
view.setTitleTextColor(titleColor);
|
view.setTitleTextColor(titleColor);
|
||||||
|
@ -102,37 +90,12 @@ public class ReactToolbarManager extends ViewGroupManager<Toolbar> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "actions")
|
@ReactProp(name = "actions")
|
||||||
public void setActions(Toolbar view, @Nullable ReadableArray actions) {
|
public void setActions(ReactToolbar view, @Nullable ReadableArray actions) {
|
||||||
Menu menu = view.getMenu();
|
view.setActions(actions);
|
||||||
menu.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));
|
|
||||||
String icon = action.hasKey(PROP_ACTION_ICON) ? action.getString(PROP_ACTION_ICON) : null;
|
|
||||||
if (icon != null) {
|
|
||||||
item.setIcon(getDrawableResourceByName(view.getContext(), icon));
|
|
||||||
}
|
|
||||||
String show = action.hasKey(PROP_ACTION_SHOW) ? action.getString(PROP_ACTION_SHOW) : null;
|
|
||||||
if (show != null) {
|
|
||||||
int showAsAction = MenuItem.SHOW_AS_ACTION_NEVER;
|
|
||||||
if ("always".equals(show)) {
|
|
||||||
showAsAction = MenuItem.SHOW_AS_ACTION_ALWAYS;
|
|
||||||
} else if ("ifRoom".equals(show)) {
|
|
||||||
showAsAction = MenuItem.SHOW_AS_ACTION_IF_ROOM;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addEventEmitters(final ThemedReactContext reactContext, final Toolbar view) {
|
protected void addEventEmitters(final ThemedReactContext reactContext, final ReactToolbar view) {
|
||||||
final EventDispatcher mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class)
|
final EventDispatcher mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class)
|
||||||
.getEventDispatcher();
|
.getEventDispatcher();
|
||||||
view.setNavigationOnClickListener(
|
view.setNavigationOnClickListener(
|
||||||
|
@ -145,7 +108,7 @@ public class ReactToolbarManager extends ViewGroupManager<Toolbar> {
|
||||||
});
|
});
|
||||||
|
|
||||||
view.setOnMenuItemClickListener(
|
view.setOnMenuItemClickListener(
|
||||||
new Toolbar.OnMenuItemClickListener() {
|
new ReactToolbar.OnMenuItemClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||||
mEventDispatcher.dispatchEvent(
|
mEventDispatcher.dispatchEvent(
|
||||||
|
@ -158,6 +121,17 @@ public class ReactToolbarManager extends ViewGroupManager<Toolbar> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public boolean needsCustomLayoutForChildren() {
|
public boolean needsCustomLayoutForChildren() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -205,12 +179,4 @@ public class ReactToolbarManager extends ViewGroupManager<Toolbar> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getDrawableResourceByName(Context context, String name) {
|
|
||||||
name = name.toLowerCase().replace("-", "_");
|
|
||||||
return context.getResources().getIdentifier(
|
|
||||||
name,
|
|
||||||
"drawable",
|
|
||||||
context.getPackageName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue