Files
Dimitris-Rafail Katsampas 966dccd0f9 feat(core): textbase span interaction and styling improvements (#10682)
- Added `linkTap` event support for other iOS views that nest spans
- Prevent android span from setting parent background color to itself since it doesn't react to changes of that property. Unless background color is specified to the span directly, it's going to be transparent
- Added few missing `nativeTextViewProtected` references
- Improved view disposal for classes that inherit from TextBase as they had leftovers after android activity recreation
- Removed 2 assignments of `userInteractionEnabled` from TextBase as they were unneeded and had conflicts with `isUserInteractionEnabled` property. Core already sets that property to true for the views that need it in `createNativeView` call
- `HTMLView` will remove extra padding using the documented `UIEdgeInsetsZero`
2025-01-31 14:00:52 -08:00

179 lines
5.1 KiB
TypeScript

import { ScrollEventData } from '.';
import { ScrollViewBase, scrollBarIndicatorVisibleProperty, isScrollEnabledProperty } from './scroll-view-common';
import { layout } from '../../utils';
import { isUserInteractionEnabledProperty } from '../core/view';
export * from './scroll-view-common';
export class ScrollView extends ScrollViewBase {
nativeViewProtected: org.nativescript.widgets.VerticalScrollView | org.nativescript.widgets.HorizontalScrollView;
private _androidViewId = -1;
private handler: android.view.ViewTreeObserver.OnScrollChangedListener;
get horizontalOffset(): number {
const nativeView = this.nativeViewProtected;
if (!nativeView) {
return 0;
}
return nativeView.getScrollX() / layout.getDisplayDensity();
}
get verticalOffset(): number {
const nativeView = this.nativeViewProtected;
if (!nativeView) {
return 0;
}
return nativeView.getScrollY() / layout.getDisplayDensity();
}
get scrollableWidth(): number {
const nativeView = this.nativeViewProtected;
if (!nativeView || this.orientation !== 'horizontal') {
return 0;
}
return nativeView.getScrollableLength() / layout.getDisplayDensity();
}
get scrollableHeight(): number {
const nativeView = this.nativeViewProtected;
if (!nativeView || this.orientation !== 'vertical') {
return 0;
}
return nativeView.getScrollableLength() / layout.getDisplayDensity();
}
[isUserInteractionEnabledProperty.setNative](value: boolean) {
// NOTE: different behavior on iOS & Android:
// iOS disables user interaction recursively for all subviews as well
this.nativeViewProtected.setClickable(value);
this.nativeViewProtected.setFocusable(value);
this.nativeViewProtected.setScrollEnabled(value);
}
[isScrollEnabledProperty.getDefault](): boolean {
return this.nativeViewProtected.getScrollEnabled();
}
[isScrollEnabledProperty.setNative](value: boolean) {
this.nativeViewProtected.setScrollEnabled(value);
}
[scrollBarIndicatorVisibleProperty.getDefault](): boolean {
return true;
}
[scrollBarIndicatorVisibleProperty.setNative](value: boolean) {
if (this.orientation === 'horizontal') {
this.nativeViewProtected.setHorizontalScrollBarEnabled(value);
} else {
this.nativeViewProtected.setVerticalScrollBarEnabled(value);
}
}
public scrollToVerticalOffset(value: number, animated: boolean) {
const nativeView = this.nativeViewProtected;
if (nativeView && this.orientation === 'vertical' && this.isScrollEnabled) {
value *= layout.getDisplayDensity();
if (animated) {
nativeView.smoothScrollTo(0, value);
} else {
nativeView.scrollTo(0, value);
}
}
}
public scrollToHorizontalOffset(value: number, animated: boolean) {
const nativeView = this.nativeViewProtected;
if (nativeView && this.orientation === 'horizontal' && this.isScrollEnabled) {
value *= layout.getDisplayDensity();
if (animated) {
nativeView.smoothScrollTo(value, 0);
} else {
nativeView.scrollTo(value, 0);
}
}
}
public createNativeView() {
if (this.orientation === 'horizontal') {
return new org.nativescript.widgets.HorizontalScrollView(this._context);
} else {
const view = new org.nativescript.widgets.VerticalScrollView(this._context);
view.setVerticalScrollBarEnabled(true);
return view;
}
}
public initNativeView(): void {
super.initNativeView();
if (this._androidViewId < 0) {
this._androidViewId = android.view.View.generateViewId();
}
this.nativeViewProtected.setId(this._androidViewId);
}
public _onOrientationChanged() {
if (this.nativeViewProtected) {
const parent = this.parent;
if (parent) {
parent._removeView(this);
parent._addView(this);
}
}
}
protected attachNative() {
if (!this.handler) {
const viewRef = new WeakRef(this);
this.handler = new android.view.ViewTreeObserver.OnScrollChangedListener({
onScrollChanged: function () {
const owner: ScrollView = viewRef.get();
if (owner) {
owner._onScrollChanged();
}
},
});
this.nativeViewProtected.getViewTreeObserver().addOnScrollChangedListener(this.handler);
}
}
private _lastScrollX = -1;
private _lastScrollY = -1;
private _onScrollChanged() {
const nativeView = this.nativeViewProtected;
if (nativeView) {
// Event is only raised if the scroll values differ from the last time in order to wokraround a native Android bug.
// https://github.com/NativeScript/NativeScript/issues/2362
const newScrollX = nativeView.getScrollX();
const newScrollY = nativeView.getScrollY();
if (newScrollX !== this._lastScrollX || newScrollY !== this._lastScrollY) {
this.notify(<ScrollEventData>{
object: this,
eventName: ScrollView.scrollEvent,
scrollX: newScrollX / layout.getDisplayDensity(),
scrollY: newScrollY / layout.getDisplayDensity(),
});
this._lastScrollX = newScrollX;
this._lastScrollY = newScrollY;
}
}
}
protected detachNative() {
if (this.handler) {
if (this.nativeViewProtected) {
this.nativeViewProtected.getViewTreeObserver().removeOnScrollChangedListener(this.handler);
}
this.handler = null;
}
}
}
ScrollView.prototype.recycleNativeView = 'never';