RadListView - images rendering incorrectly

Thread is closed for posting
5 posts, 1 answers
  1. Stan
    Stan avatar
    40 posts
    Member since:
    May 2017

    Posted 03 Jul 2017 Link to this post

    I have a folder with 57 image files (no dups): 

    • On an Android real device (Samsung Note3) the pics are duplicated randomly
    • On an iOS simulator some pics are overlapping it's boundaries

    Please see photos. Is there a better way to do this to fix the problems?

    Thanks.

    package.json

    {
      "description": "NativeScript Application",
      "license": "SEE LICENSE IN <your-license-filename>",
      "readme": "NativeScript Application",
      "repository": "<fill-your-repository-here>",
      "nativescript": {
        "id": "org.nativescript.FolderList",
        "tns-android": {
          "version": "3.0.0"
        }
      },
      "dependencies": {
        "nativescript-telerik-ui": "^2.0.1",
        "nativescript-theme-core": "~1.0.2",
        "tns-core-modules": "^3.0.0"
      },
      "devDependencies": {
        "babel-traverse": "6.4.5",
        "babel-types": "6.4.5",
        "babylon": "6.4.5",
        "lazy": "1.0.11",
        "nativescript-dev-android-snapshot": "^0.*.*"
      }
    }

    main-page.xml

    <Page xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:lv="nativescript-telerik-ui/listview" loaded="pageLoaded">
        <ActionBar title="RadListView FolderList" />
        <lv:RadListView loaded="lvloaded" items="{{ myItems }}" itemLoading="func">
            <lv:RadListView.listViewLayout>
                <lv:ListViewGridLayout scrollDirection="Vertical" spanCount="3"/>
            </lv:RadListView.listViewLayout>
            <lv:RadListView.itemTemplate>
                <Image id="pic" decodeWidth="100" decodeHeight="100" loadMode="async" height="100" width="100" class="item-template-style" />
            </lv:RadListView.itemTemplate>
        </lv:RadListView>
    </Page>

    main-page.js

    var observable_1 = require("data/observable");
    var fs = require("file-system");
    var listView_1 = require("nativescript-telerik-ui/listview");

    var myImages = [];

    var viewModel = new observable_1.Observable();
        viewModel.set("myItems", myImages);

    exports.pageLoaded = function(args) {
        readFiles();
        var page = args.object;
        page.bindingContext = viewModel;
    }

    exports.func = function(args) {
        var layout = args.view;
        var image = layout.getViewById("pic");
        image.src = myImages[args.itemIndex];
    }

    function lvloaded(args) {
        var listview = args.object;
        listview.on(listView_1.RadListView.itemTapEvent, function (args) {
            console.log("selected item index " + args.itemIndex);
        });
    }
    exports.lvloaded = lvloaded;

    function readFiles() {
        var documents = fs.knownFolders.currentApp();
        var myFolder = documents.getFolder("img");
        var array = myFolder.getEntitiesSync();
        array.forEach(function (element) {
            myImages.push(element._path);
        });
    }

  2. Nikolay Iliev
    Admin
    Nikolay Iliev avatar
    351 posts

    Posted 04 Jul 2017 Link to this post

    Hi Stan,

    Thank you for contacting us and providing good snippets.
    There are two main issues that can be resolved to improve both the duplicating images on Android and the overlapping in iOS.In the lines below I am going to cover both problems separately. For your convenience, I have created this test project to demonstrate the solutions based on your snippets.

    Regarding the duplicated images on Android

    The issue here is that you are assigning the image src property using itemLoading event. This is not a good practice and in fact, is breaking the main purposes of ListView and RadListView - the virtualization and recycling. As the recycling is trying to reuse cells when possible but you are assigning the image src in an event called after the recycling it leads to the unwanted duplicated photos.More about fast list-views, virtualization, and recycling can be found in this blog post

    The solution to this problem is assigning the src of your images (inside each list view item template) in advance or even better - use binding model with observed just as you are attaching the source array itself.
    .e.g
    <Image src="{{ path }}"  />

    Where path is just a key-value pair I have created when pushing your paths. Notice that now I am using ObservableArray so that if you need to change the array (add/remove items) the source array will be notified and the UI will be updated. The example in my test application is using 4 different photos loaded locally but the principle would be the same when using photos from a different location.

    Regarding the overlapping images in iOS.

    The issue here is because when using Item Layouts for RadListView you need to use itemWidth and itemHeight for iOS. So the solution would be to set your itemWidth and itemHeight instead of setting width and height of your image or item template.
    e.g.
    <lv:ListViewGridLayout scrollDirection="Vertical" spanCount="3" itemHeight="100" itemWidth="100"/>

    You can still use decodeWidth and decodeHeight for  Android (they won't make difference for iOS) but you will have to set explicitly the itemWidth and itemHeight to overcome the dynamically assigned size of your templates.

    Regards,
    Nikolay Iliev
    Progress Telerik
    Did you know that you can open private support tickets which are reviewed and answered within 24h by the same team who built the components? This is available in our UI for NativeScript Pro + Support offering.
  3. Stan
    Stan avatar
    40 posts
    Member since:
    May 2017

    Posted 10 Jul 2017 in reply to Nikolay Iliev Link to this post

    Hi Nikolay,

    Thanks so much for your insights! I'm new to NativeScript and I really appreciate it.
    My images no longer overlap in the iOS simulator, I would have never figured out to use itemHeight and itemWidth for iOS. Thanks for that!
    My images are in a folder called ~/img and the number of images it has changes. So I have to use knownFolders.currentApp() to fill the array.
    The following code:
    Works in the iOS simulator and Android emulator (same Android version as my real device)
    Still not working on my Android real device (Samsung Note3 Android ver 5.0). Still duplicating images (please see attached).
    I've also noticed a new problem now, when I make any changes to the code all the images load again (appended to the bottom) so I have multiple sets. Is there a way to stop that? My next step is listViewItemTap to detail page and display a full image, I don't want to navigate back and get another set of images appended to the bottom. Any help you can give me will be greatly appreciated.
    Thanks so much...

    package.json
    {
      "description": "NativeScript Application",
      "license": "SEE LICENSE IN <your-license-filename>",
      "readme": "NativeScript Application",
      "repository": "<fill-your-repository-here>",
      "nativescript": {
        "id": "org.nativescript.FolderList",
        "tns-android": {
          "version": "3.0.0"
        }
      },
      "dependencies": {
        "nativescript-telerik-ui": "^2.0.1",
        "nativescript-theme-core": "~1.0.2",
        "tns-core-modules": "^3.0.0"
      },
      "devDependencies": {
        "babel-traverse": "6.4.5",
        "babel-types": "6.4.5",
        "babylon": "6.4.5",
        "lazy": "1.0.11",
        "nativescript-dev-android-snapshot": "^0.*.*"
      }
    }

    main-page.xml

    <Page xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:lv="nativescript-telerik-ui/listview" loaded="pageLoaded">
        <ActionBar title="RadListView FolderList" />
        <lv:RadListView loaded="lvloaded" items="{{ myItems }}">
            <lv:RadListView.listViewLayout>
                <lv:ListViewGridLayout scrollDirection="Vertical" itemHeight="100" itemWidth="100" spanCount="3"/>
            </lv:RadListView.listViewLayout>
            <lv:RadListView.itemTemplate>
                <!-- Need loadMode="async" for Android emulator or get OutOfMemory error  -->
                <Image src="{{ path }}" loadMode="async" class="item-template-style" height="100" width="100"/>
            </lv:RadListView.itemTemplate>
        </lv:RadListView>
    </Page>

    main-page.js

    var observable_1 = require("data/observable");
    var fs = require("file-system");
    var listView_1 = require("nativescript-telerik-ui/listview");
    var ObservableArray = require("data/observable-array").ObservableArray;

    var myImages = new ObservableArray();
    var viewModel = new observable_1.Observable();
        viewModel.set("myItems", myImages);

    exports.pageLoaded = function(args) {
        readFiles();
        var page = args.object;
        page.bindingContext = viewModel;
    }

    exports.lvloaded = function(args) {
        var listview = args.object;
        listview.on(listView_1.RadListView.itemTapEvent, function (args) {
            console.log("selected item index " + args.itemIndex);
        });
    }

    function readFiles() {
        var documents = fs.knownFolders.currentApp();
        var myFolder = documents.getFolder("img");
        var array = myFolder.getEntitiesSync();
        array.forEach(function (element) {
            myImages.push({path: element._path});
        });
    }

     

  4. Answer
    Nikolay Iliev
    Admin
    Nikolay Iliev avatar
    351 posts

    Posted 11 Jul 2017 Link to this post

    Hello Stan,

    Regarding the issue with duplicating images

    We have modified my test application so that it will use the same workflow for loading images (via local folder using the file-system module) but still was not able to reproduce the issue with duplicated images. We have tested on few different phones (including some old models like LG g2 and Samsung S3) + multiple emulators but the issue was not observed on any of them,
    Would it be possible to retest the case using the provided test application we have created? Also, try to completely uninstall the app from your test Samsung Note and then rebuild and redeploy the application just to exclude any local caching issues.

    Regarding the issue with images loading again in multiple sets

    The issue is caused by the fact that in the project the initialization of the array of image paths in the loaded callback. Each time the user navigates, the loaded event will be triggered and the method readFiles will be called again.
    There are multiple solutions to this problem. The first one would be to check if an image path is unique and if not no to push it again (this means that you have to know the name of files). Another possible solution is to reset the observable array and push the array of paths in a brand new empty array.
    e.g.
    function readFiles() {
        var documents = fs.knownFolders.currentApp();
        var myFolder = documents.getFolder("images");
        var arr = myFolder.getEntitiesSync();
     
        myImagePaths = new ObservableArray(); // reset the array so now it will contain 0 iamges
     
        arr.forEach(function (element) {
            myImagePaths.push({path: element._path}); // push each image again
               // if you prefer the first approach you can do the check here
               // (e.g. pseudo code if(!pathExists) push; else don't push)
        });
     
        viewModel.set("myItems", myImagePaths); // set the array in the view-model
    }



    Regards,
    Nikolay Iliev
    Progress Telerik
    Did you know that you can open private support tickets which are reviewed and answered within 24h by the same team who built the components? This is available in our UI for NativeScript Pro + Support offering.
  5. Stan
    Stan avatar
    40 posts
    Member since:
    May 2017

    Posted 18 Jul 2017 in reply to Nikolay Iliev Link to this post

    Thanks for your help. The rebuild and redeploy the application did the trick on my real device.

    Your suggestions also took care of my images loading in multiple sets.

    A big thanks to you!

Back to Top