mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
fix: Don't crash on missing resources in tab-view and action-bar (#6388)
This commit is contained in:
committed by
GitHub
parent
5b77017d37
commit
56a1b120af
@@ -9,7 +9,13 @@ import { profile } from "../../profiling";
|
||||
|
||||
export * from "../core/view";
|
||||
|
||||
import { View, ViewBase, Property, unsetValue, booleanConverter, horizontalAlignmentProperty, verticalAlignmentProperty, CSSType } from "../core/view";
|
||||
import {
|
||||
View, ViewBase, Property,
|
||||
unsetValue, booleanConverter,
|
||||
horizontalAlignmentProperty,
|
||||
verticalAlignmentProperty, CSSType,
|
||||
traceWrite, traceCategories, traceMessageType
|
||||
} from "../core/view";
|
||||
|
||||
export module knownCollections {
|
||||
export var actionItems = "actionItems";
|
||||
@@ -334,6 +340,12 @@ function onVisibilityChanged(item: ActionItemBase, oldValue: string, newValue: s
|
||||
item._onVisibilityChanged(newValue);
|
||||
}
|
||||
|
||||
export function traceMissingIcon(icon: string) {
|
||||
traceWrite("Could not load action bar icon: " + icon,
|
||||
traceCategories.Error,
|
||||
traceMessageType.error);
|
||||
}
|
||||
|
||||
export const textProperty = new Property<ActionItemBase, string>({ name: "text", defaultValue: "", valueChanged: onItemChanged });
|
||||
textProperty.register(ActionItemBase);
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { AndroidActionBarSettings as AndroidActionBarSettingsDefinition, AndroidActionItemSettings } from ".";
|
||||
import { ActionItemBase, ActionBarBase, isVisible, View, layout, colorProperty, flatProperty, Color } from "./action-bar-common";
|
||||
import {
|
||||
ActionItemBase, ActionBarBase, isVisible,
|
||||
View, layout, colorProperty, flatProperty,
|
||||
Color, traceMissingIcon
|
||||
} from "./action-bar-common";
|
||||
import { RESOURCE_PREFIX } from "../../utils/utils";
|
||||
import { fromFileOrResource } from "../../image-source";
|
||||
import * as application from "../../application";
|
||||
@@ -18,7 +22,7 @@ function generateItemId(): number {
|
||||
}
|
||||
|
||||
interface MenuItemClickListener {
|
||||
new (owner: ActionBar): android.support.v7.widget.Toolbar.OnMenuItemClickListener;
|
||||
new(owner: ActionBar): android.support.v7.widget.Toolbar.OnMenuItemClickListener;
|
||||
}
|
||||
|
||||
let appResources: android.content.res.Resources;
|
||||
@@ -219,7 +223,9 @@ export class ActionBar extends ActionBarBase {
|
||||
}
|
||||
else if (navButton.icon) {
|
||||
let drawableOrId = getDrawableOrResourceId(navButton.icon, appResources);
|
||||
this.nativeViewProtected.setNavigationIcon(drawableOrId);
|
||||
if (drawableOrId) {
|
||||
this.nativeViewProtected.setNavigationIcon(drawableOrId);
|
||||
}
|
||||
}
|
||||
|
||||
// Set navigation content descripion, used by screen readers for the vision-impaired users
|
||||
@@ -304,9 +310,6 @@ export class ActionBar extends ActionBarBase {
|
||||
if (drawableOrId) {
|
||||
menuItem.setIcon(drawableOrId);
|
||||
}
|
||||
else {
|
||||
throw new Error("Error loading icon from " + item.icon);
|
||||
}
|
||||
}
|
||||
|
||||
let showAsAction = getShowAsAction(item);
|
||||
@@ -422,10 +425,11 @@ function getDrawableOrResourceId(icon: string, resources: android.content.res.Re
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let result = undefined;
|
||||
if (icon.indexOf(RESOURCE_PREFIX) === 0) {
|
||||
let resourceId: number = resources.getIdentifier(icon.substr(RESOURCE_PREFIX.length), "drawable", application.android.packageName);
|
||||
if (resourceId > 0) {
|
||||
return resourceId;
|
||||
result = resourceId;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -436,10 +440,14 @@ function getDrawableOrResourceId(icon: string, resources: android.content.res.Re
|
||||
drawable = new android.graphics.drawable.BitmapDrawable(is.android);
|
||||
}
|
||||
|
||||
return drawable;
|
||||
result = drawable;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
if (!result) {
|
||||
traceMissingIcon(icon);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getShowAsAction(menuItem: ActionItem): number {
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
import { IOSActionItemSettings, ActionItem as ActionItemDefinition } from ".";
|
||||
import { ActionItemBase, ActionBarBase, isVisible, View, colorProperty, backgroundColorProperty, backgroundInternalProperty, flatProperty, layout, Color } from "./action-bar-common";
|
||||
import { ImageSource, fromFileOrResource } from "../../image-source";
|
||||
import {
|
||||
ActionItemBase, ActionBarBase, isVisible, View,
|
||||
colorProperty, backgroundColorProperty,
|
||||
backgroundInternalProperty, flatProperty,
|
||||
layout, Color, traceMissingIcon } from "./action-bar-common";
|
||||
import { fromFileOrResource } from "../../image-source";
|
||||
import { ios as iosUtils } from "../../utils/utils";
|
||||
import { write as traceWrite, categories, messageType } from "../../trace";
|
||||
|
||||
export * from "./action-bar-common";
|
||||
|
||||
const majorVersion = iosUtils.MajorVersion;
|
||||
const UNSPECIFIED = layout.makeMeasureSpec(0, layout.UNSPECIFIED);
|
||||
|
||||
function loadActionIconFromFileOrResource(icon: string): UIImage {
|
||||
const img = fromFileOrResource(icon);
|
||||
if (img && img.ios) {
|
||||
return img.ios;
|
||||
} else {
|
||||
traceMissingIcon(icon);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class TapBarItemHandlerImpl extends NSObject {
|
||||
private _owner: WeakRef<ActionItemDefinition>;
|
||||
|
||||
@@ -151,16 +166,16 @@ export class ActionBar extends ActionBarBase {
|
||||
}
|
||||
|
||||
// Set back button image
|
||||
let img: ImageSource;
|
||||
let img: UIImage;
|
||||
if (this.navigationButton && isVisible(this.navigationButton) && this.navigationButton.icon) {
|
||||
img = fromFileOrResource(this.navigationButton.icon);
|
||||
img = loadActionIconFromFileOrResource(this.navigationButton.icon);
|
||||
}
|
||||
|
||||
// TODO: This could cause issue when canceling BackEdge gesture - we will change the backIndicator to
|
||||
// show the one from the old page but the new page will still be visible (because we canceled EdgeBackSwipe gesutre)
|
||||
// Consider moving this to new method and call it from - navigationControllerDidShowViewControllerAnimated.
|
||||
if (img && img.ios) {
|
||||
let image = img.ios.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
|
||||
if (img) {
|
||||
let image = img.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
|
||||
navigationBar.backIndicatorImage = image;
|
||||
navigationBar.backIndicatorTransitionMaskImage = image;
|
||||
} else {
|
||||
@@ -226,12 +241,8 @@ export class ActionBar extends ActionBarBase {
|
||||
|
||||
barButtonItem = UIBarButtonItem.alloc().initWithBarButtonSystemItemTargetAction(id, tapHandler, "tap");
|
||||
} else if (item.icon) {
|
||||
const img = fromFileOrResource(item.icon);
|
||||
if (img && img.ios) {
|
||||
barButtonItem = UIBarButtonItem.alloc().initWithImageStyleTargetAction(img.ios, UIBarButtonItemStyle.Plain, tapHandler, "tap");
|
||||
} else {
|
||||
throw new Error("Error loading icon from " + item.icon);
|
||||
}
|
||||
const img = loadActionIconFromFileOrResource(item.icon);
|
||||
barButtonItem = UIBarButtonItem.alloc().initWithImageStyleTargetAction(img, UIBarButtonItemStyle.Plain, tapHandler, "tap");
|
||||
} else {
|
||||
barButtonItem = UIBarButtonItem.alloc().initWithTitleStyleTargetAction(item.text + "", UIBarButtonItemStyle.Plain, tapHandler, "tap");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { TabView as TabViewDefinition, TabViewItem as TabViewItemDefinition, SelectedIndexChangedEventData } from ".";
|
||||
import {
|
||||
View, ViewBase, Style, Property, CssProperty, CoercibleProperty,
|
||||
Color, isIOS, AddArrayFromBuilder, AddChildFromBuilder, EventData, CSSType
|
||||
Color, isIOS, AddArrayFromBuilder, AddChildFromBuilder, EventData, CSSType,
|
||||
traceWrite, traceCategories, traceMessageType
|
||||
} from "../core/view";
|
||||
|
||||
export * from "../core/view";
|
||||
@@ -203,6 +204,10 @@ export interface TabViewBase {
|
||||
on(event: "selectedIndexChanged", callback: (args: SelectedIndexChangedEventData) => void, thisArg?: any);
|
||||
}
|
||||
|
||||
export function traceMissingIcon(icon: string) {
|
||||
traceWrite("Could not load tab bar icon: " + icon, traceCategories.Error, traceMessageType.error);
|
||||
}
|
||||
|
||||
export const selectedIndexProperty = new CoercibleProperty<TabViewBase, number>({
|
||||
name: "selectedIndex", defaultValue: -1, affectsLayout: isIOS,
|
||||
valueChanged: (target, oldValue, newValue) => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
tabTextColorProperty, tabBackgroundColorProperty, tabTextFontSizeProperty, selectedTabTextColorProperty,
|
||||
androidSelectedTabHighlightColorProperty, androidOffscreenTabLimitProperty,
|
||||
fontSizeProperty, fontInternalProperty, layout, traceCategory, traceEnabled,
|
||||
traceWrite, Color
|
||||
traceWrite, Color, traceMissingIcon
|
||||
} from "./tab-view-common"
|
||||
import { textTransformProperty, TextTransform, getTransformedText } from "../text-base";
|
||||
import { fromFileOrResource } from "../../image-source";
|
||||
@@ -233,11 +233,16 @@ function createTabItemSpec(item: TabViewItem): org.nativescript.widgets.TabItemS
|
||||
if (item.iconSource) {
|
||||
if (item.iconSource.indexOf(RESOURCE_PREFIX) === 0) {
|
||||
result.iconId = ad.resources.getDrawableId(item.iconSource.substr(RESOURCE_PREFIX.length));
|
||||
if (result.iconId === 0) {
|
||||
traceMissingIcon(item.iconSource);
|
||||
}
|
||||
} else {
|
||||
const is = fromFileOrResource(item.iconSource);
|
||||
if (is) {
|
||||
// TODO: Make this native call that accepts string so that we don't load Bitmap in JS.
|
||||
result.iconDrawable = new android.graphics.drawable.BitmapDrawable(is.android);
|
||||
} else {
|
||||
traceMissingIcon(item.iconSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ios as iosView, ViewBase } from "../core/view";
|
||||
import {
|
||||
TabViewBase, TabViewItemBase, itemsProperty, selectedIndexProperty,
|
||||
tabTextColorProperty, tabTextFontSizeProperty, tabBackgroundColorProperty, selectedTabTextColorProperty, iosIconRenderingModeProperty,
|
||||
View, fontInternalProperty, layout, traceEnabled, traceWrite, traceCategories, Color
|
||||
View, fontInternalProperty, layout, traceEnabled, traceWrite, traceCategories, Color, traceMissingIcon
|
||||
} from "./tab-view-common"
|
||||
import { textTransformProperty, TextTransform, getTransformedText } from "../text-base";
|
||||
import { fromFileOrResource } from "../../image-source";
|
||||
@@ -451,6 +451,8 @@ export class TabView extends TabViewBase {
|
||||
const originalRenderedImage = is.ios.imageWithRenderingMode(this._getIconRenderingMode());
|
||||
this._iconsCache[iconSource] = originalRenderedImage;
|
||||
image = originalRenderedImage;
|
||||
} else {
|
||||
traceMissingIcon(iconSource);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user