NativeScript:显示 ActivityIndicator 时禁用所有控件

问题描述 投票:0回答:6

假设有一个带有用户名\密码文本字段和登录按钮的登录页面。按下按钮时,将向服务器设置请求并显示 ActivityIndicator。 目前,我将 StackLayout 放在所有其他控件之上,以免用户在处理请求时单击它们。但在某些情况下,TextField 保持焦点,用户可以在那里键入。

我已经使用一个组件来包装所有 TextFields 以显示验证错误:

@Component({
  selector: "field",
  template: "<grid-layout><ng-content></ng-content>...</grid-layout>"
})
export class FieldComponent {
  @ContentChild(NgModel) private input: NgModel;
  ...
}

我的问题是我可以将

ng-content
内的 TextField 上的 isEnabled 属性设置为 false 吗? 如果不可能,在这种情况下,当应用程序繁忙时禁用输入的最佳实践是什么?
    
这是我的 NativeScript+Angular 解决方案:

android angular nativescript angular2-nativescript
6个回答
4
投票
setControlInteractionState() 是递归的。

TextField 光标被隐藏(使用原生 Android API)。
  1. XML:

FieldComponent

NgModel

打字稿:


<GridLayout #mainGrid rows="*" columns="*"> <!-- Main page content here... --> <GridLayout *ngIf="isBusy" rows="*" columns="*"> <GridLayout rows="*" columns="*" style="background-color: black; opacity: 0.35"> </GridLayout> <ActivityIndicator width="60" height="60" busy="true"> </ActivityIndicator> </GridLayout> </GridLayout> NS 2.5.0


有几种方法可以做到这一点;


3
投票

您可以使用

<GridLayout #mainGrid rows="*" columns="*"> <!-- Main page content here... --> </GridLayout> <GridLayout *ngIf="isBusy" rows="*" columns="*"> <GridLayout rows="*" columns="*" style="background-color: black; opacity: 0.35"> </GridLayout> <ActivityIndicator width="60" height="60" busy="true"> </ActivityIndicator> </GridLayout>
    或绑定
  1. import { Component, ViewChild, ElementRef } from "@angular/core"; import { View } from "ui/core/view"; import { LayoutBase } from "ui/layouts/layout-base"; import { isAndroid, isIOS } from "platform"; @Component({ templateUrl: "./SignIn.html" }) export class SignInComponent { @ViewChild("mainGrid") MainGrid: ElementRef; isBusy: boolean = false; submit() : void { try { this.isBusy = true; setControlInteractionState(<View>this.MainGrid.nativeElement, false); //sign-in here... } finally { this.isBusy = false; setControlInteractionState(<View>this.MainGrid.nativeElement, true); } } setControlInteractionState(view: View, isEnabled: boolean) : void { view.isUserInteractionEnabled = isEnabled; if (isAndroid) { if (view.android instanceof android.widget.EditText) { let control = <android.widget.EditText>view.android; control.setCursorVisible(isEnabled); } } if (view instanceof LayoutBase) { let layoutBase = <LayoutBase>view; for (let i = 0, length = layoutBase.getChildrenCount(); i < length; i++) { let child = layoutBase.getChildAt(i); setControlInteractionState(child, isEnabled); } } } }

    根据数据绑定值禁用它。

    
    
    您可以创建一个您调用的简单例程(我的首选方法)。

  2. ngIf

isEnabled
插件具有 runAgainst* 或 getElementBy* 包装器来与本机层对话,就像与 html dom 对话一样。 

完全公开,我是

require("nativescript-dom"); 
function screenEnabled(isEnabled) {
       runAgainstTagNames('TextEdit', function(e) { e.isEnabled = isEnabled; });
       runAgainstTagNames('Button', function(e) { e.isEnabled = isEnabled; }); 
}
的作者,它是我在几乎每个应用程序/演示中使用的插件之一。

我在 Angular 中找到了一个最简单的解决方案,所以我在这里发布以供将来参考。首先在 

nativescript-dom

1
投票
nativescript-dom

,如下所示:


app.component.html

注意网格内的

ScrollView
。默认情况下,它将放置在 row="0" 处。接下来是 
<GridLayout> <page-router-outlet></page-router-outlet> <!-- hack to block UI --> <ScrollView isUserInteractionEnabled="false" *ngIf="isLoading"> <ActivityIndicator busy="true"></ActivityIndicator> </ScrollView> </GridLayout>

,它的 isUserInteractionEnabled 设置为 false。 现在,在您的

page-router-outlet
文件中添加一个名为
ScrollView
的变量,并使用某种事件(例如 RxJs Observable 事件)切换它。

扩展@KTCO的答案以使覆盖层的大小与主网格完全相同:

app.component.ts

0
投票

我知道这有点老了,但有时我只能按照自己的方式做事。如果您想以编程方式完成此操作:

isLoading

0
投票
注意:这不会禁用/启用初始

import { Size, View } from "tns-core-modules/ui/core/view"; import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout/grid-layout"; ... ... dialogSize: Size; mainGrid: GridLayout; ... submit() { this.mainGrid = <GridLayout>this.MainGrid.nativeElement; this.dialogSize = this.mainGrid.getActualSize(); ..... ..... <GridLayout *ngIf="isBusy" rows="auto" columns="auto"> <GridLayout rows="*" columns="*" [width]="dialogSize.width" [height]="dialogSize.height" style="background-color: black; opacity: 0.35"> </GridLayout> <ActivityIndicator width="50" height="50" busy="true"> </ActivityIndicator> </GridLayout>

(即本例中的

const excludedView = someViewToBeExcluded;

const enabler = (parentView:View, enable:boolean) => {
  parentView.eachChildView(childView => {
    if (childView != excludedView) {
      enabler(childView, enable);
      childView.isEnabled = enable;
    }          
    return true;
  });
};

enabler(page, false);


只是添加一些更多信息。每个 
parentView

都有一个

0
投票

isUserInteractionEnabled

 属性。
isEnabled:获取或设置一个值,指示视图是否启用。这会影响视图的

外观
  • isUserInteractionEnabled:获取或设置一个值,指示用户是否可以与视图交互。这不会影响视图的外观。
  • 在 Angular 中,我做了类似的事情: page
  • 然后在组件中您可以启用/禁用,例如:

View

我还在 
<Button text="Tap Me!" (tap)="onBtnTapped($event)" [isEnabled]="isEnabled$ |async" [isUserInteractionEnabled]="isEnabled$ |async" ></Button>

isEnabled$ = new BehaviorSubject(true); this.isEnabled$.next(true); // Enable this.isEnabled$.next(false); // Disable
 上设置了 
isEnabled

,以同时将一堆子视图灰显。从我所看到的来看,它似乎不会像

GridLayout
那样影响子视图,因此可能需要在每个视图上单独设置,但我可能是错的。
    

© www.soinside.com 2019 - 2024. All rights reserved.