ListView not addapting on iOS


#1

My Listview works perfectly on Android.
But when i move the project to iOS. the ListView gets completely bugged. Like i will show down below:


The List should expande and show several StackLayouts. Instead its like if all the StackLayouts became 1 and stayed on top of the page.
And there’s just an empty space in all that middle of the screen.

My Html code:

<GridLayout rows="*, auto">
  <StackLayout row="0">
    <ActionBar fontSize="30" title="Movimentos" color="white">
      <NavigationButton text="" android.systemIcon="ic_menu_back" (tap)="onNavBtnTap()" [nsRouterLink]="['/main']" pageTransition="slideRight"></NavigationButton>
      <ActionItem (tap)="onEdit()" icon="res://ic_today_white" ios.position="right" visibility="{{ isEditing ? 'collapse' : 'visible' }}"
        [nsRouterLink]="['/main']" pageTransition="fade"></ActionItem>
    </ActionBar>
    <ListView [items]="everything" (loadMoreItems)="loadMoreItems()" flexGrow="1">
      <ng-template let-item="item">
        <StackLayout (tap)="details(item.id,item.idDocumento)" marginTop="20" marginLeft="20" marginRight="20" marginBottom="10"
          backgroundColor="white" [nsRouterLink]="['/main']" pageTransition="slide" borderRadius="5%">
          <GridLayout rows="auto auto auto" columns="* 75">
            <Label class="labelTransactionType" text="{{item.idDocumento}}" textWrap="true" row="0" col="0" marginTop="10"></Label>
            <Label class="labelTransactionValue" text="{{item.value}}" textWrap="true" row="1" col="0"></Label>
            <Label class="transactionsButtons" text=">" row="1" col="1" marginTop="-5"></Label>
            <Label class="labelTransactionData" text="{{item.date}}" textWrap="true" row="2" col="0" marginBottom="10"></Label>
          </GridLayout>
        </StackLayout>
      </ng-template>
      </ListView>
  </StackLayout>
  <BottomBar row="1" [items]="items" [hide]="hidden" [titleState]="titleState" (loaded)="tabLoaded($event)" (tabSelected)="tabSelected($event)"
    [inactiveColor]="inactiveColor" [accentColor]="accentColor" colored="true"></BottomBar>
</GridLayout>

My component.ts code:

import { Page } from "ui/page";
import { Component, OnInit } from "@angular/core";
import { registerElement } from 'nativescript-angular';
import { BottomBar, BottomBarItem, TITLE_STATE, SelectedIndexChangedEventData, Notification } from 'nativescript-bottombar';
import { NavigationButton } from "ui/action-bar";
import { User } from "../../shared/model/user/user";
import { UserService } from "../../shared/model/user/user.service";
import { MovementService } from "../../shared/model/movement/movement.service";
import { Router, NavigationExtras } from "@angular/router";
import * as colorModule from "tns-core-modules/color";
import { ActivatedRoute } from "@angular/router";
import * as platformModule from "tns-core-modules/platform";
import { screen } from "tns-core-modules/platform/platform"
import * as absoluteLayoutModule from "tns-core-modules/ui/layouts/absolute-layout";
import { EventData, Observable } from "data/observable";
import { setTimeout } from "timer";
import { ScrollEventData } from "ui/scroll-view";
var applicationSettings = require("application-settings");


@Component({
  selector: "transactions",
  providers: [UserService, MovementService],
  templateUrl: "pages/transactions/transactions.html",
  styleUrls: ["pages/transactions/transactions-common.css", "pages/transactions/transactions.css"]
})
export class TransactionsComponent implements OnInit {
  public hidden: boolean;
  public titleState: TITLE_STATE;
  public _bar: BottomBar;
  public inactiveColor: string;
  public accentColor: string;
  public user: User;
  public screenHeight: number;
  public screenWidth: number;
  public test: string;
  public id: string[];
  public date: string[];
  public idDocumento: string[];
  public value: number[];
  public everything: any[] = new Array();
  public monthNames = ["Janeiro ", "Fevereiro", "Março", "Abril", "Maio", "Junho",
    "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"
  ];
  public status = "not scrolling";
  public idDetailedMovement: string;
  public price: string;
  public quantity: string;
  public what: string;
  public counter: number = 0;
  public counterOriginalValue: number = 0;



  constructor(private router: Router, private page: Page, private route: ActivatedRoute, private userService: UserService, private movementService: MovementService) {
    this.route.queryParams.subscribe(params => {
      this.user = JSON.parse(params["user"]);
    })
  }

  public items: Array<BottomBarItem> = [
    new BottomBarItem(0, "Início", "ic_home", "white"),
    new BottomBarItem(1, "Transações", "ic_assignment", "white"),
    new BottomBarItem(2, "Pagar", "ic_add_a_photo", "white"),
    new BottomBarItem(3, "Definições", "ic_settings", "white")
];

  tabLoaded(event) {
    this._bar = <BottomBar>event.object;
    this.hidden = false;
    this.titleState = TITLE_STATE.ALWAYS_SHOW;
    var Color = colorModule.Color;
    var color = new Color("#8e8e93");
    this.inactiveColor = color.hex;
    this.accentColor = "black";
    //this._bar.selectItem(3);
    this._bar.selectItem(1);
  }

  ngOnInit() {

    this.page.actionBarHidden = false;
    this.page.backgroundImage = "res://bitmap";

    this.showTransactions("1");
  }

  showTransactions(pageNumber) {
    let navigationExtras: NavigationExtras = {
      queryParams: {
        "user": JSON.stringify({
          "name": this.user.name,
          "nif": this.user.nif,
          "password": this.user.password
        })
      }
    };

    //MovementPage direct to API
    this.movementService.movementPageAPI(applicationSettings.getString("user.token", "default"), pageNumber)
      .subscribe(res => {
        this.counterOriginalValue++;
        if (res._body.length == 0 && pageNumber == 1) {
          alert("Este utente não tem movimentos!");
          this.router.navigate(["/homePage"], navigationExtras);
        } else {
          if (res._body.length == 1) {
            var date = res._body[0].Data.toString();
            var arr = new Array();
            arr = date.split("-");
            arr[1] = arr[1].substring(1);
            var auxArr = new Array();
            auxArr = arr[2].split("T");

            res._body[0].Valor = this.changeValue(res._body[0].TipoDoc, res._body[0].Valor);
            res._body[0].TipoDoc = this.changeLanguage(res._body[0].TipoDoc);


            this.everything.push({
              id: (res._body[0].Id).toString(),
              date: ("Data: " + auxArr[0] + " de " + this.monthNames[arr[1] - 1] + " de " + arr[0]),
              idDocumento: (res._body[0].TipoDoc).toString(),
              value: (res._body[0].Valor).toString()
            });
          } else {
            if (res._body.length == 10) {
              this.counter++;
            }
            for (var i = 0; i < res._body.length; i++) {

              var date = res._body[i].Data.toString();
              var arr = new Array();
              arr = date.split("-");
              arr[1] = arr[1].substring(1);
              var auxArr = new Array();
              auxArr = arr[2].split("T");

              res._body[i].Valor = this.changeValue(res._body[i].TipoDoc, res._body[i].Valor);
              res._body[i].TipoDoc = this.changeLanguage(res._body[i].TipoDoc);


              this.everything.push({
                id: (res._body[i].Id).toString(),
                date: ("Data: " + auxArr[0] + " de " + this.monthNames[arr[1] - 1] + " de " + arr[0]),
                idDocumento: (res._body[i].TipoDoc).toString(),
                value: (res._body[i].Valor).toString()
              });
            }
            this.router.navigate(["/transactions"], navigationExtras);
          }
        }
      },
      (error) => alert("Sem ligação de dados ativa. Verifique as ligações de dados móveis ou Wi-fi e tente novamente")
      );

  }


  changeLanguage(string) {
    if (string == "Pagamento") {
      return (string = "Pagamento");
    }
    if (string == "Carregamento") {
      return (string = "Carregamento");
    }
    if (string == "Estorno") {
      return (string = "Estorno");
    }
  }

  changeValue(string, num) {
    var decimalcases = this.decimalPlaces(num);
    if (Number.isInteger(num)) {
      num = num + ".00";
    } else {
      var number = this.decimalPlaces(num);
      if (number == 1) {
        num = num + "0";
      } else {
      }
    }
    if (string == "Pagamento") {
      return (num = "- €" + num);
    }
    if (string == "Carregamento") {
      return (num = "+ €" + num);
    }
    if (string == "Estorno") {
      return (num = "+ €" + num);
    }
  }

  decimalPlaces(num) {
    var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
    if (!match) { return 0; }
    return Math.max(
      0,
      // Number of digits right of decimal point.
      (match[1] ? match[1].length : 0)
      // Adjust for scientific notation.
      - (match[2] ? +match[2] : 0));
  }

  tabSelected(args: SelectedIndexChangedEventData) {
    switch (args.newIndex) {
        case 0: {
            let navigationExtras: NavigationExtras = {
                queryParams: {
                    "user": JSON.stringify({
                        "name": this.user.name,
                        "nif": this.user.nif,
                        "password": this.user.password
                    })
                }
            };
            this.router.navigate(["/homePage"], navigationExtras);
            break;
        }
        case 1: {
            let navigationExtras: NavigationExtras = {
                queryParams: {
                    "user": JSON.stringify({
                        "name": this.user.name,
                        "nif": this.user.nif,
                        "password": this.user.password
                    })
                }
            };
            this.router.navigate(["/transactions"], navigationExtras);
            break;
        }
        case 2: {
            let navigationExtras: NavigationExtras = {
                queryParams: {
                    "user": JSON.stringify({
                        "name": this.user.name,
                        "nif": this.user.nif,
                        "password": this.user.password
                    })
                }
            };
            this.router.navigate(["/payment"], navigationExtras);
            break;
        }
        case 3: {
            let navigationExtras: NavigationExtras = {
                queryParams: {
                    "user": JSON.stringify({
                        "name": this.user.name,
                        "nif": this.user.nif,
                        "password": this.user.password
                    })
                }
            };
            this.router.navigate(["/userSettings"], navigationExtras);
            break;
        }
    }
}

  details(string1, string2) {
    let navigationExtras: NavigationExtras = {
      queryParams: {
        "user": JSON.stringify({
          "name": this.user.name,
          "nif": this.user.nif,
          "password": this.user.password
        }),
        "movementID": string1,
        "type": string2,
      }
    };

    if (string2 == "Pagamento") {
      this.router.navigate(["/paymentDetails"], navigationExtras);
    }

    if (string2 == "Estorno") {
      this.router.navigate(["/refundDetails"], navigationExtras);
    }

    if (string2 == "Carregamento") {
      this.router.navigate(["/bankTransferDetails"], navigationExtras);
    }
  }

  onNavBtnTap() {
    let navigationExtras: NavigationExtras = {
      queryParams: {
        "user": JSON.stringify({
          "name": this.user.name,
          "nif": this.user.nif,
          "password": this.user.password
        })
      }
    };
    this.router.navigate(["/homePage"], navigationExtras);
  }

  onEdit() {
    let navigationExtras: NavigationExtras = {
      queryParams: {
        "user": JSON.stringify({
          "name": this.user.name,
          "nif": this.user.nif,
          "password": this.user.password
        })
      }
    };
    this.router.navigate(["/dateTransaction"], navigationExtras);
  }


  public onScroll(args: ScrollEventData) {
    this.status = "scrolling";

    //ao dar scroll movements by Page 2,3,4,5,...
    setTimeout(() => {
      this.status = "not scrolling";
    }, 300);

    console.log("scrollX: " + args.scrollX);
    console.log("scrollY: " + args.scrollY);

    if (args.scrollY == 929) {
      console.log("Want to see more movements");
    }
  }

  loadMoreItems() {
    if (this.counter == this.counterOriginalValue) {
      this.showTransactions((this.counter + 1));
    }
  }

}

On Android the code is the same and i dont have to tecnically set a height for the ListView.
How do i get for the ListView to expand properly on iOS? It should of expand.

Tecnically every 1 on 10 times it expands. the other 9 it doesn’t.

If anyone could give a hino i woulda appreciate. Thanks.


#2

If i set a height on the ListView on iOS it works. But it doesn’t make sense to set a height. It should adjust…
On Android it worked nicely.


#3

Anyone have an answer to this yet? I’ve tried setting the height to the .length of my arrays * by height of each row, but it’s never correct. It really should just expand dynamically the way Android does - any help would be appreciated! :slight_smile:

@Eddy @NathanaelA @manojdcoder


#4

ActionBar usually placed as direct child of Page element and you are nesting the layouts too much, the StackLayout above ListView is unnecessary and might be the reason for your issue.