Merge pull request #1068 from NativeScript/scrol-view-scroll-event

ScrollView scroll event
This commit is contained in:
Vladimir Enchev
2015-11-10 15:39:14 +02:00
5 changed files with 276 additions and 22 deletions

View File

@@ -265,6 +265,98 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
// Check verticalOffset after navigation
TKUnit.assertAreClose(this.testView.horizontalOffset, 100, 0.1, "this.testView.horizontalOffset after navigation");
}
public test_scrollView_vertical_raised_scroll_event() {
this.testView.orientation = enums.Orientation.vertical;
var scrollY: number;
this.testView.on(scrollViewModule.ScrollView.scrollEvent, (args: scrollViewModule.ScrollEventData) => {
scrollY = args.scrollY;
});
this.testView.width = 200;
this.testView.height = 300;
var btn = new button.Button();
btn.text = "test";
btn.height = 500;
this.testView.content = btn;
this.waitUntilTestElementLayoutIsValid();
this.testView.scrollToVerticalOffset(100, false);
TKUnit.waitUntilReady(function () { return scrollY > 0; });
TKUnit.assertEqual(scrollY, this.testView.verticalOffset);
}
public test_scrollView_horizontal_raised_scroll_event() {
this.testView.orientation = enums.Orientation.horizontal;
var scrollX: number;
this.testView.on(scrollViewModule.ScrollView.scrollEvent, (args: scrollViewModule.ScrollEventData) => {
scrollX = args.scrollX;
});
this.testView.width = 200;
this.testView.height = 300;
var btn = new button.Button();
btn.text = "test";
btn.width = 500;
this.testView.content = btn;
this.waitUntilTestElementLayoutIsValid();
this.testView.scrollToHorizontalOffset(100, false);
TKUnit.waitUntilReady(function () { return scrollX > 0; });
TKUnit.assertEqual(scrollX, this.testView.horizontalOffset);
}
public test_scrollView_vertical_raised_scroll_event_after_loaded() {
this.testView.orientation = enums.Orientation.vertical;
this.waitUntilTestElementIsLoaded();
var scrollY: number;
this.testView.on(scrollViewModule.ScrollView.scrollEvent, (args: scrollViewModule.ScrollEventData) => {
scrollY = args.scrollY;
});
this.testView.width = 200;
this.testView.height = 300;
var btn = new button.Button();
btn.text = "test";
btn.height = 500;
this.testView.content = btn;
this.waitUntilTestElementLayoutIsValid();
this.testView.scrollToVerticalOffset(100, false);
TKUnit.waitUntilReady(function () { return scrollY > 0; });
TKUnit.assertEqual(scrollY, this.testView.verticalOffset);
}
public test_scrollView_horizontal_raised_scroll_event_after_loaded() {
this.testView.orientation = enums.Orientation.horizontal;
this.waitUntilTestElementIsLoaded();
var scrollX: number;
this.testView.on(scrollViewModule.ScrollView.scrollEvent, (args: scrollViewModule.ScrollEventData) => {
scrollX = args.scrollX;
});
this.testView.width = 200;
this.testView.height = 300;
var btn = new button.Button();
btn.text = "test";
btn.width = 500;
this.testView.content = btn;
this.waitUntilTestElementLayoutIsValid();
this.testView.scrollToHorizontalOffset(100, false);
TKUnit.waitUntilReady(function () { return scrollX > 0; });
TKUnit.assertEqual(scrollX, this.testView.horizontalOffset);
}
}
export function createTestCase(): ScrollLayoutTest {

View File

@@ -1,6 +1,8 @@
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import enums = require("ui/enums");
import definition = require("ui/scroll-view");
import contentView = require("ui/content-view");
function isValidOrientation(value: any): boolean {
return value === enums.Orientation.vertical || value === enums.Orientation.horizontal;
@@ -13,4 +15,90 @@ export var orientationProperty = new dependencyObservable.Property(
dependencyObservable.PropertyMetadataSettings.AffectsLayout,
undefined,
isValidOrientation)
);
);
export class ScrollView extends contentView.ContentView implements definition.ScrollView {
private _scrollChangeCount: number = 0;
public static scrollEvent = "scroll";
get orientation(): string {
return this._getValue(orientationProperty);
}
set orientation(value: string) {
this._setValue(orientationProperty, value);
}
public addEventListener(arg: string, callback: any, thisArg?: any) {
super.addEventListener(arg, callback, thisArg);
if (arg === definition.ScrollView.scrollEvent) {
this._scrollChangeCount++;
this.attach();
}
}
public removeEventListener(arg: string, callback: any, thisArg?: any) {
super.addEventListener(arg, callback, thisArg);
if (arg === definition.ScrollView.scrollEvent) {
this._scrollChangeCount--;
this.dettach();
}
}
public onLoaded() {
super.onLoaded();
this.attach();
}
public onUnloaded() {
super.onUnloaded();
this.dettach();
}
private attach() {
if (this._scrollChangeCount > 0 && this.isLoaded) {
this.attachNative();
}
}
private dettach() {
if (this._scrollChangeCount === 0 && this.isLoaded) {
this.dettachNative();
}
}
protected attachNative() {
//
}
protected dettachNative() {
//
}
get horizontalOffset(): number {
return 0;
}
get verticalOffset(): number {
return 0;
}
get scrollableWidth(): number {
return 0;
}
get scrollableHeight(): number {
return 0;
}
public scrollToVerticalOffset(value: number, animated: boolean) {
//
}
public scrollToHorizontalOffset(value: number, animated: boolean) {
//
}
}

View File

@@ -1,9 +1,9 @@
import dependencyObservable = require("ui/core/dependency-observable");
import definition = require("ui/scroll-view");
import contentView = require("ui/content-view");
import common = require("./scroll-view-common");
import utils = require("utils/utils");
import enums = require("ui/enums");
import proxy = require("ui/core/proxy");
global.moduleMerge(common, exports);
@@ -11,9 +11,10 @@ common.orientationProperty.metadata.onValueChanged = function scrollViewOrientat
(<ScrollView>data.object)._onOrientationChanged(data.oldValue, data.newValue);
}
export class ScrollView extends contentView.ContentView implements definition.ScrollView {
export class ScrollView extends common.ScrollView implements definition.ScrollView {
private _android: org.nativescript.widgets.VerticalScrollView | org.nativescript.widgets.HorizontalScrollView;
private _androidViewId: number;
private handler: android.view.ViewTreeObserver.OnScrollChangedListener;
get android(): android.view.ViewGroup {
return this._android;
@@ -23,13 +24,6 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
return this._android;
}
get orientation(): string {
return this._getValue(common.orientationProperty);
}
set orientation(value: string) {
this._setValue(common.orientationProperty, value);
}
get horizontalOffset(): number {
if (!this._android) {
return 0;
@@ -68,8 +62,7 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
if (animated) {
this._android.smoothScrollTo(0, value);
}
else {
} else {
this._android.scrollTo(0, value);
}
}
@@ -81,8 +74,7 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
if (animated) {
this._android.smoothScrollTo(value, 0);
}
else {
} else {
this._android.scrollTo(value, 0);
}
}
@@ -91,8 +83,7 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
public _createUI() {
if (this.orientation === enums.Orientation.horizontal) {
this._android = new org.nativescript.widgets.HorizontalScrollView(this._context);
}
else {
} else {
this._android = new org.nativescript.widgets.VerticalScrollView(this._context);
}
@@ -116,4 +107,28 @@ export class ScrollView extends contentView.ContentView implements definition.Sc
}
}
}
protected attachNative() {
var that = new WeakRef(this);
this.handler = new android.view.ViewTreeObserver.OnScrollChangedListener({
onScrollChanged: function () {
var rootScrollView = that.get();
if (rootScrollView && rootScrollView.android) {
rootScrollView.notify(<definition.ScrollEventData>{
object: rootScrollView,
eventName: definition.ScrollView.scrollEvent,
scrollX: rootScrollView.android.getScrollX() / utils.layout.getDisplayDensity(),
scrollY: rootScrollView.android.getScrollY() / utils.layout.getDisplayDensity()
});
}
}
});
this._android.getViewTreeObserver().addOnScrollChangedListener(this.handler);
}
protected dettachNative() {
this._android.getViewTreeObserver().removeOnScrollChangedListener(this.handler);
this.handler = null;
}
}

View File

@@ -3,11 +3,22 @@
*/
declare module "ui/scroll-view" {
import contentView = require("ui/content-view");
import observable = require("data/observable");
import dependencyObservable = require("ui/core/dependency-observable");
export var orientationProperty: dependencyObservable.Property;
/**
* Represents a scrollable area that can have content that is larger than its bounds.
*/
class ScrollView extends contentView.ContentView {
public static orientationProperty: dependencyObservable.Property;
/**
* String value used when hooking to scroll event.
*/
public static scrollEvent: string;
/**
* Gets a value that contains the vertical offset of the scrolled content.
*/
@@ -46,5 +57,23 @@ declare module "ui/scroll-view" {
* Gets or sets direction in which the content can be scrolled.
*/
orientation: string;
/**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
* @param eventNames - String corresponding to events (e.g. "propertyChange"). Optionally could be used more events separated by `,` (e.g. "propertyChange", "change").
* @param callback - Callback function which will be executed when event is raised.
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
*/
on(eventNames: string, callback: (data: observable.EventData) => void, thisArg?: any);
/**
* Raised when a scroll event occurs.
*/
on(event: "scroll", callback: (args: ScrollEventData) => void, thisArg?: any);
}
interface ScrollEventData extends observable.EventData {
scrollX: number;
scrollY: number;
}
}

View File

@@ -1,27 +1,57 @@
import view = require("ui/core/view");
import definition = require("ui/scroll-view");
import contentView = require("ui/content-view");
import common = require("./scroll-view-common");
import enums = require("ui/enums");
import utils = require("utils/utils");
global.moduleMerge(common, exports);
export class ScrollView extends contentView.ContentView implements definition.ScrollView {
class UIScrollViewDelegateImpl extends NSObject implements UIScrollViewDelegate {
private _owner: WeakRef<ScrollView>;
public static initWithOwner(owner: WeakRef<ScrollView>): UIScrollViewDelegateImpl {
let impl = <UIScrollViewDelegateImpl>UIScrollViewDelegateImpl.new();
impl._owner = owner;
return impl;
}
public scrollViewDidScroll(sv: UIScrollView): void {
let owner = this._owner.get();
if (!owner) {
return;
}
if (owner) {
owner.notify(<definition.ScrollEventData>{
object: owner,
eventName: definition.ScrollView.scrollEvent,
scrollX: owner.horizontalOffset,
scrollY: owner.verticalOffset
});
}
}
public static ObjCProtocols = [UIScrollViewDelegate];
}
export class ScrollView extends common.ScrollView implements definition.ScrollView {
private _scroll: UIScrollView;
private _contentMeasuredWidth: number = 0;
private _contentMeasuredHeight: number = 0;
private _delegate: UIScrollViewDelegateImpl;
constructor() {
super();
this._scroll = new UIScrollView();
}
get orientation(): string {
return this._getValue(common.orientationProperty);
protected attachNative() {
this._delegate = UIScrollViewDelegateImpl.initWithOwner(new WeakRef(this));
this._scroll.delegate = this._delegate;
}
set orientation(value: string) {
this._setValue(common.orientationProperty, value);
protected dettachNative() {
this._scroll.delegate = null;
}
get horizontalOffset(): number {