mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(android): clickable span
Initial support for clickable span on Android
This commit is contained in:
10
tns-core-modules/text/span.d.ts
vendored
10
tns-core-modules/text/span.d.ts
vendored
@@ -50,6 +50,16 @@ export class Span extends ViewBase {
|
||||
* Gets or sets the text for the span.
|
||||
*/
|
||||
public text: string;
|
||||
|
||||
/**
|
||||
* String value used when hooking to linkClicked event.
|
||||
*/
|
||||
public static linkClickedEvent: string;
|
||||
|
||||
/**
|
||||
* Gets if the span is clickable or not.
|
||||
*/
|
||||
public readonly clickable: boolean;
|
||||
|
||||
//@private
|
||||
/**
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
import { Span as SpanDefinition } from "./span";
|
||||
import { ViewBase } from "../ui/core/view";
|
||||
import { FontStyle, FontWeight, } from "../ui/styling/font";
|
||||
import { TextDecoration } from "../ui/text-base";
|
||||
import { TextDecoration, EventData } from "../ui/text-base";
|
||||
|
||||
export class Span extends ViewBase implements SpanDefinition {
|
||||
static linkClickEvent = "linkClick";
|
||||
private _text: string;
|
||||
private _clickable: boolean = false;
|
||||
|
||||
get fontFamily(): string {
|
||||
return this.style.fontFamily;
|
||||
@@ -68,7 +70,29 @@ export class Span extends ViewBase implements SpanDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
get clickable(): boolean {
|
||||
return this._clickable;
|
||||
}
|
||||
|
||||
addEventListener(arg: string, callback: (data: EventData) => void, thisArg?: any) {
|
||||
console.log(arg);
|
||||
super.addEventListener(arg, callback, thisArg);
|
||||
this._setClickable(this.hasListeners(Span.linkClickEvent));
|
||||
}
|
||||
|
||||
removeEventListener(arg: string, callback?: any, thisArg?: any) {
|
||||
super.removeEventListener(arg, callback, thisArg);
|
||||
this._setClickable(this.hasListeners(Span.linkClickEvent));
|
||||
}
|
||||
|
||||
_setTextInternal(value: string): void {
|
||||
this._text = value;
|
||||
}
|
||||
|
||||
private _setClickable(value: boolean): void {
|
||||
if (this._clickable !== value) {
|
||||
this._clickable = value;
|
||||
this.notifyPropertyChange("clickable", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,41 @@ function initializeTextTransformation(): void {
|
||||
TextTransformation = TextTransformationImpl;
|
||||
}
|
||||
|
||||
interface ClickableSpan {
|
||||
new (owner: Span): android.text.style.ClickableSpan;
|
||||
}
|
||||
|
||||
let ClickableSpan: ClickableSpan;
|
||||
|
||||
function initializeClickableSpan(): void {
|
||||
if (ClickableSpan) {
|
||||
return;
|
||||
}
|
||||
|
||||
class ClickableSpanImpl extends android.text.style.ClickableSpan {
|
||||
owner: WeakRef<Span>;
|
||||
|
||||
constructor(owner: Span) {
|
||||
super();
|
||||
this.owner = new WeakRef(owner);
|
||||
return global.__native(this);
|
||||
}
|
||||
onClick(view: android.view.View): void {
|
||||
const owner = this.owner.get();
|
||||
if (owner) {
|
||||
owner.notify({ eventName: Span.linkClickEvent, object: owner });
|
||||
}
|
||||
view.clearFocus();
|
||||
view.invalidate();
|
||||
}
|
||||
updateDrawState(tp: android.text.TextPaint): void {
|
||||
// don't style as link
|
||||
}
|
||||
}
|
||||
|
||||
ClickableSpan = ClickableSpanImpl;
|
||||
}
|
||||
|
||||
export class TextBase extends TextBaseCommon {
|
||||
nativeViewProtected: android.widget.TextView;
|
||||
nativeTextViewProtected: android.widget.TextView;
|
||||
@@ -57,12 +92,15 @@ export class TextBase extends TextBaseCommon {
|
||||
private _maxHeight: number;
|
||||
private _minLines: number;
|
||||
private _maxLines: number;
|
||||
private _clickable: boolean = false;
|
||||
private _defaultMovementMethod: android.text.method.MovementMethod;
|
||||
|
||||
public initNativeView(): void {
|
||||
super.initNativeView();
|
||||
initializeTextTransformation();
|
||||
const nativeView = this.nativeTextViewProtected;
|
||||
this._defaultTransformationMethod = nativeView.getTransformationMethod();
|
||||
this._defaultMovementMethod = this.nativeView.getMovementMethod();
|
||||
this._minHeight = nativeView.getMinHeight();
|
||||
this._maxHeight = nativeView.getMaxHeight();
|
||||
this._minLines = nativeView.getMinLines();
|
||||
@@ -108,6 +146,7 @@ export class TextBase extends TextBaseCommon {
|
||||
if (!reset && this.formattedText) {
|
||||
return;
|
||||
}
|
||||
this._setClickableState(false);
|
||||
|
||||
this._setNativeText(reset);
|
||||
}
|
||||
@@ -128,6 +167,7 @@ export class TextBase extends TextBaseCommon {
|
||||
|
||||
const spannableStringBuilder = createSpannableStringBuilder(value);
|
||||
nativeView.setText(<any>spannableStringBuilder);
|
||||
this._setClickableState(isStringClickable(value));
|
||||
|
||||
textProperty.nativeValueChange(this, (value === null || value === undefined) ? "" : value.toString());
|
||||
|
||||
@@ -310,6 +350,19 @@ export class TextBase extends TextBaseCommon {
|
||||
|
||||
this.nativeTextViewProtected.setText(<any>transformedText);
|
||||
}
|
||||
|
||||
_setClickableState(clickable: boolean) {
|
||||
if (this._clickable !== clickable) {
|
||||
this._clickable = clickable;
|
||||
if (this._clickable) {
|
||||
this.nativeViewProtected.setMovementMethod(android.text.method.LinkMovementMethod.getInstance());
|
||||
this.nativeViewProtected.setHighlightColor(null);
|
||||
}
|
||||
else {
|
||||
this.nativeViewProtected.setMovementMethod(this._defaultMovementMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCapitalizedString(str: string): string {
|
||||
@@ -341,6 +394,19 @@ export function getTransformedText(text: string, textTransform: TextTransform):
|
||||
}
|
||||
}
|
||||
|
||||
function isStringClickable(formattedString: FormattedString) {
|
||||
if (!formattedString) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0, length = formattedString.spans.length; i < length; i++) {
|
||||
const span = formattedString.spans.getItem(i);
|
||||
if (span.clickable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function createSpannableStringBuilder(formattedString: FormattedString): android.text.SpannableStringBuilder {
|
||||
if (!formattedString) {
|
||||
return null;
|
||||
@@ -439,6 +505,12 @@ function setSpanModifiers(ssb: android.text.SpannableStringBuilder, span: Span,
|
||||
}
|
||||
}
|
||||
|
||||
const clickable = span.clickable;
|
||||
if (clickable) {
|
||||
initializeClickableSpan();
|
||||
ssb.setSpan(new ClickableSpan(span), start, end, android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
// TODO: Implement letterSpacing for Span here.
|
||||
// const letterSpacing = formattedString.parent.style.letterSpacing;
|
||||
// if (letterSpacing > 0) {
|
||||
|
||||
Reference in New Issue
Block a user