NativeScript:显示ActivityIndi​​cator时禁用所有控件

时间:2016-12-06 04:59:08

标签: android angular nativescript angular2-nativescript

假设有一个登录页面,其中包含用户名\密码TextFields和登录按钮。按下按钮时,会向服务器设置一个请求,并显示ActivityIndi​​cator。 目前,我将StackLayout放在所有其他控件之上,不让用户在处理请求时单击它们。但在某些情况下,TextField会保持专注,用户可以在那里输入。

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

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

我的问题是,我可以在来自ng-content FieldComponent NgModel的{​​{1}}内的TextField上以某种方式将isEnabled属性设置为false吗? 如果不可能,在这种情况下,当应用程序繁忙时禁用输入的最佳做法是什么?

5 个答案:

答案 0 :(得分:3)

以下是我对NativeScript + Angular的解决方案:

  1. setControlInteractionState()是递归的。
  2. 隐藏TextField游标(使用本机android API)。
  3. <强> XML:

    <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>
    

    <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>
    

    <强>打字稿:

    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);
                }
            }
        }
    
    }
    

    NS 2.5.0

答案 1 :(得分:2)

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

  1. 您可以使用YOUR_DATE_VARIABLE.to_s(:human_with_12hours)ngIf上的绑定根据数据绑定值禁用它。

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

  3. isEnabled

    require("nativescript-dom"); function screenEnabled(isEnabled) { runAgainstTagNames('TextEdit', function(e) { e.isEnabled = isEnabled; }); runAgainstTagNames('Button', function(e) { e.isEnabled = isEnabled; }); } 插件有runAgainst *或getElementBy *包装器与本机层对话,就像你在与html dom谈话一样。

    完全披露,我是nativescript-dom的作者,它是我在几乎所有应用/演示中使用的插件之一。

答案 2 :(得分:0)

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

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>

答案 3 :(得分:0)

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


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(在此示例中为page

答案 4 :(得分:0)

我在Angular中找到了最简单的解决方案,因此我在这里发布以供将来参考。首先在app.component.html文件中添加一个网格和ScrollView,如下所示:

 <GridLayout>
    <page-router-outlet></page-router-outlet>
    <!-- hack to block UI -->
    <ScrollView isUserInteractionEnabled="false" *ngIf="isLoading">
        <ActivityIndicator busy="true"></ActivityIndicator>     
    </ScrollView>
</GridLayout>

请注意位于网格内部的page-router-outlet。默认情况下,它将放置在row =“ 0”。接下来是ScrollView,其isUserInteractionEnabled设置为false。 现在,在您的app.component.ts文件中添加一个名为isLoading的变量,并使用某种事件(例如RxJs可观察事件)将其切换