Merge branch 'ios-safe-area' of github.com:NativeScript/NativeScript into ios-safe-area

This commit is contained in:
Vasil Chimev
2018-09-21 16:43:13 +03:00
36 changed files with 362 additions and 85 deletions

View File

@@ -253,7 +253,15 @@ export abstract class ViewBase extends Observable {
public bind(options: BindingOptions, source?: Object): void;
public unbind(property: string): void;
/**
* Invalidates the layout of the view and triggers a new layout pass.
*/
public requestLayout(): void;
/**
* Iterates over children of type ViewBase.
* @param callback Called for each child of type ViewBase. Iteration stops if this method returns falsy value.
*/
public eachChild(callback: (child: ViewBase) => boolean): void;
public _addView(view: ViewBase, atIndex?: number): void;

View File

@@ -595,13 +595,13 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
}
public loadView(view: ViewBase): void {
if (!view.isLoaded) {
if (view && !view.isLoaded) {
view.callLoaded();
}
}
public unloadView(view: ViewBase): void {
if (view.isLoaded) {
if (view && view.isLoaded) {
view.callUnloaded();
}
}

View File

@@ -1,7 +1,6 @@
// Definitions.
import { Point, CustomLayoutView as CustomLayoutViewDefinition, dip } from ".";
import { GestureTypes, GestureEventData } from "../../gestures";
import { AndroidActivityBackPressedEventData } from "../../../application";
// Types.
import {
ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty,
@@ -22,6 +21,7 @@ import {
import { Background, ad as androidBackground } from "../../styling/background";
import { profile } from "../../../profiling";
import { topmost } from "../../frame/frame-stack";
import { AndroidActivityBackPressedEventData, android as androidApp } from "../../../application";
export * from "./view-common";
@@ -72,12 +72,7 @@ function initializeTouchListener(): void {
onTouch(view: android.view.View, event: android.view.MotionEvent): boolean {
const owner = this.owner;
for (let type in owner._gestureObservers) {
let list = owner._gestureObservers[type];
list.forEach(element => {
element.androidOnTouchEvent(event);
});
}
owner.handleGestureTouch(event);
let nativeView = owner.nativeViewProtected;
if (!nativeView || !nativeView.onTouchEvent) {
@@ -112,6 +107,13 @@ function initializeDialogFragment() {
activity: view._context,
cancel: false,
};
// Fist fire application.android global event
androidApp.notify(args);
if (args.cancel) {
return;
}
view.notify(args);
if (!args.cancel && !view.onBackPressed()) {
@@ -178,7 +180,7 @@ function initializeDialogFragment() {
}
const owner = this.owner;
if (!owner.isLoaded) {
if (owner && !owner.isLoaded) {
owner.callLoaded();
}
@@ -194,7 +196,7 @@ function initializeDialogFragment() {
}
const owner = this.owner;
if (owner.isLoaded) {
if (owner && owner.isLoaded) {
owner.callUnloaded();
}
}
@@ -320,6 +322,18 @@ export class View extends ViewCommon {
return false;
}
public handleGestureTouch(event: android.view.MotionEvent): any {
for (let type in this._gestureObservers) {
let list = this._gestureObservers[type];
list.forEach(element => {
element.androidOnTouchEvent(event);
});
}
if (this.parent instanceof View) {
this.parent.handleGestureTouch(event);
}
}
private hasGestureObservers() {
return this._gestureObservers && Object.keys(this._gestureObservers).length > 0
}
@@ -343,15 +357,20 @@ export class View extends ViewCommon {
}
private setOnTouchListener() {
if (this.nativeViewProtected && this.hasGestureObservers()) {
this.touchListenerIsSet = true;
if (this.nativeViewProtected.setClickable) {
this.nativeViewProtected.setClickable(true);
}
if (!this.nativeViewProtected || !this.hasGestureObservers()) {
return;
}
// do not set noop listener that handles the event (disabled listener) if IsUserInteractionEnabled is
// false as we might need the ability for the event to pass through to a parent view
initializeTouchListener();
this.touchListener = this.touchListener || new TouchListener(this);
this.nativeViewProtected.setOnTouchListener(this.touchListener);
initializeTouchListener();
this.touchListener = this.touchListener || new TouchListener(this);
this.nativeViewProtected.setOnTouchListener(this.touchListener);
this.touchListenerIsSet = true;
if (this.nativeViewProtected.setClickable) {
this.nativeViewProtected.setClickable(this.isUserInteractionEnabled);
}
}
@@ -490,7 +509,7 @@ export class View extends ViewCommon {
public getLocationRelativeTo(otherView: ViewCommon): Point {
if (!this.nativeViewProtected || !this.nativeViewProtected.getWindowToken() ||
!otherView.nativeViewProtected || !otherView.nativeViewProtected.getWindowToken() ||
!otherView || !otherView.nativeViewProtected || !otherView.nativeViewProtected.getWindowToken() ||
this.nativeViewProtected.getWindowToken() !== otherView.nativeViewProtected.getWindowToken()) {
return undefined;
}
@@ -591,15 +610,8 @@ export class View extends ViewCommon {
}
[isUserInteractionEnabledProperty.setNative](value: boolean) {
if (!value) {
initializeDisabledListener();
// User interaction is disabled -- we stop it and we do not care whether someone wants to listen for gestures.
this.nativeViewProtected.setOnTouchListener(disableUserInteractionListener);
} else {
this.setOnTouchListener();
if (!this.touchListenerIsSet) {
this.nativeViewProtected.setOnTouchListener(null);
}
if (this.nativeViewProtected.setClickable) {
this.nativeViewProtected.setClickable(value);
}
}

View File

@@ -585,7 +585,11 @@ export abstract class View extends ViewBase {
_getNativeViewsCount(): number;
_eachLayoutView(callback: (View) => void): void;
/**
* Iterates over children of type View.
* @param callback Called for each child of type View. Iteration stops if this method returns falsy value.
*/
public eachChildView(callback: (view: View) => boolean): void;
//@private

View File

@@ -1,4 +1,4 @@
// Definitions.
// Definitions.
import { Point, View as ViewDefinition, dip } from ".";
import { ViewBase } from "../view-base";
import { booleanConverter, Property } from "../view";

View File

@@ -531,6 +531,10 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
public _onLivesync(): boolean {
super._onLivesync();
if (!this._currentEntry || !this._currentEntry.entry) {
return false;
}
const currentEntry = this._currentEntry.entry;
const newEntry: NavigationEntry = {
animated: false,

View File

@@ -9,7 +9,7 @@ import { Page } from "../page";
import * as application from "../../application";
import {
FrameBase, stack, goBack, View, Observable,
traceEnabled, traceWrite, traceCategories
traceEnabled, traceWrite, traceCategories, traceError
} from "./frame-common";
import {
@@ -138,7 +138,7 @@ export class Frame extends FrameBase {
// In this case call _navigateCore in order to recreate the current fragment.
// Don't call navigate because it will fire navigation events.
// As JS instances are alive it is already done for the current page.
if (!this.isLoaded || !this._attachedToWindow) {
if (!this.isLoaded || this._executingEntry || !this._attachedToWindow) {
return;
}
@@ -696,8 +696,23 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
}
const entry = this.entry;
if (!entry) {
traceError(`${fragment}.onCreateView: entry is null or undefined`);
return null;
}
const page = entry.resolvedPage;
if (!page) {
traceError(`${fragment}.onCreateView: entry has no resolvedPage`);
return null;
}
const frame = this.frame;
if (!frame) {
traceError(`${fragment}.onCreateView: this.frame is null or undefined`);
return null;
}
if (page.parent === frame) {
// If we are navigating to a page that was destroyed
// reinitialize its UI.
@@ -706,12 +721,12 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks {
page._setupUI(context);
}
} else {
if (!this.frame._styleScope) {
if (!frame._styleScope) {
// Make sure page will have styleScope even if parents don't.
page._updateStyleScope();
}
this.frame._addView(page);
frame._addView(page);
}
if (frame.isLoaded && !page.isLoaded) {

View File

@@ -106,6 +106,7 @@ export class LayoutBaseCommon extends CustomLayoutView implements LayoutBaseDefi
}
public clipToBounds: boolean;
public isPassThroughParentEnabled: boolean;
public _childIndexToNativeChildIndex(index?: number): number {
if (index === undefined) {
@@ -151,3 +152,6 @@ export class LayoutBaseCommon extends CustomLayoutView implements LayoutBaseDefi
export const clipToBoundsProperty = new Property<LayoutBaseCommon, boolean>({ name: "clipToBounds", defaultValue: true, valueConverter: booleanConverter });
clipToBoundsProperty.register(LayoutBaseCommon);
export const isPassThroughParentEnabledProperty = new Property<LayoutBaseCommon, boolean>({ name: "isPassThroughParentEnabled", defaultValue: false, valueConverter: booleanConverter });
isPassThroughParentEnabledProperty.register(LayoutBaseCommon);

View File

@@ -1,5 +1,5 @@
import {
LayoutBaseCommon, clipToBoundsProperty,
LayoutBaseCommon, clipToBoundsProperty, isPassThroughParentEnabledProperty,
paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty, Length
} from "./layout-base-common";
@@ -25,6 +25,10 @@ export class LayoutBase extends LayoutBaseCommon {
console.warn(`clipToBounds with value false is not supported on Android. You can use this.android.getParent().setClipChildren(false) as an alternative`);
}
[isPassThroughParentEnabledProperty.setNative](value: boolean) {
(<any>this.nativeViewProtected).setPassThroughParent(value);
}
[paddingTopProperty.getDefault](): Length {
return { value: this._defaultPaddingTop, unit: "px" };
}

View File

@@ -96,6 +96,14 @@ export class LayoutBase extends CustomLayoutView {
* Gets or sets a value indicating whether to clip the content of this layout.
*/
clipToBounds: boolean;
/**
* Gets or sets a value indicating whether touch event should pass through to a parent view of the
* layout container in case an interactive child view did not handle it.
* Default value of this property is false. This does not affect the appearance of the view.
*/
isPassThroughParentEnabled: boolean;
}
export const clipToBoundsProperty: Property<LayoutBase, boolean>;
export const isPassThroughParentEnabledProperty: Property<LayoutBase, boolean>;

View File

@@ -1,10 +1,9 @@
import { LayoutBaseCommon, clipToBoundsProperty, View, layout } from "./layout-base-common";
import { ios as iosUtils } from "../../utils/utils";
import {
LayoutBaseCommon, clipToBoundsProperty, isPassThroughParentEnabledProperty, View
} from "./layout-base-common";
export * from "./layout-base-common";
const majorVersion = iosUtils.MajorVersion;
export class LayoutBase extends LayoutBaseCommon {
nativeViewProtected: UIView;
@@ -37,4 +36,8 @@ export class LayoutBase extends LayoutBaseCommon {
[clipToBoundsProperty.setNative](value: boolean) {
this._setNativeClipToBounds();
}
[isPassThroughParentEnabledProperty.setNative](value: boolean) {
(<any>this.nativeViewProtected).setPassThroughParent(value);
}
}

View File

@@ -357,7 +357,7 @@ export class CssState {
* As a result, at some point in time, the selectors matched have to be requerried from the style scope and applied to the view.
*/
public onChange(): void {
if (this.view.isLoaded) {
if (this.view && this.view.isLoaded) {
this.unsubscribeFromDynamicUpdates();
this.updateMatch();
this.subscribeForDynamicUpdates();