Figure 1: RadListView layouts

10 posts, 3 answers
  1. Stan
    Stan avatar
    38 posts
    Member since:
    May 2017

    Posted 05 Aug Link to this post

    I'm new to NativeScript & RadListView. I was drawn to NativeScript because of this picture and I'd to know how did they did this? At first I thought it was done with multiple itemTempletes but then I remember seeing this before multiple itemTempletes were available.

    There is no documentation, or code, for this sample layout:
    http://docs.telerik.com/devtools/nativescript-ui/Controls/NativeScript/ListView/overview#different-layouts

    The SDK sample linear & Grid layouts are different.

  2. Answer
    Nikolay Iliev
    Admin
    Nikolay Iliev avatar
    324 posts

    Posted 07 Aug Link to this post

    Hello Stan,

    The example you are referring to is implemented with Telerik UI for Android which is a different product from the NativeScript UI. Although they are using almost identical RadListView implementation there are some functionalit8ites which are available only in one product and not the other. 

    With RadListView for NativeScript, you can set header and footer for your vertical list views as done in this example from the SDK application. However, this would allow you to create headers and footers for vertically aligned items. 

    To achieve the result from the first image (groped items - each group with its own header) you can approach the issue by using two separate list views (with horizontal alignment) and provide a custom made label as a header for each RadListView.
    e.g. (pseudo code based on this example)
    <GridLayout rows="50, *, 50, *" columns="">
         
        <Label row="0" text="First Group" textWrap="true" />
        <lv:RadListView row="1" items="{{ dataItems }}" >
            <lv:RadListView.listViewLayout>
                <lv:ListViewLinearLayout scrollDirection="Horizontal"/>
            </lv:RadListView.listViewLayout>
            <lv:RadListView.itemTemplate>
                <StackLayout orientation="vertical">
                    <Label fontSize="20" text="{{ itemName }}"/>
                    <Label fontSize="14" text="{{ itemDescription }}"/>
                </StackLayout>
            </lv:RadListView.itemTemplate>
        </lv:RadListView>
     
        <Label row="2" text="Second Group" textWrap="true" />
        <lv:RadListView row="3" items="{{ dataItems }}" >
            <lv:RadListView.listViewLayout>
                <lv:ListViewLinearLayout scrollDirection="Horizontal"/>
            </lv:RadListView.listViewLayout>
            <lv:RadListView.itemTemplate>
                <StackLayout orientation="vertical">
                    <Label fontSize="20" text="{{ itemName }}"/>
                    <Label fontSize="14" text="{{ itemDescription }}"/>
                </StackLayout>
            </lv:RadListView.itemTemplate>
        </lv:RadListView>
     
    </GridLayout>


    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
    38 posts
    Member since:
    May 2017

    Posted 14 Aug in reply to Nikolay Iliev Link to this post

    Thank you so much for that! It worked great.

    I would have never figured out to use rows="50, *, 50, *" in the GridLayout.

  4. Stan
    Stan avatar
    38 posts
    Member since:
    May 2017

    Posted 15 Aug in reply to Nikolay Iliev Link to this post

    Follow up question:

    This works great when I have 2 groups, or 3 in portrait mode, but when I have 5 or 6 groups can this be done with a StackLayout and ScrollView in conjunction with RadListView?

    Thank you in advance.

  5. Answer
    Deyan
    Admin
    Deyan avatar
    2147 posts

    Posted 16 Aug Link to this post

    Hello Stan,

    Thanks for writing back.

    You should be able to achieve the discussed scenario with a ScrollView provided that the horizontal scrolling of it is disabled (so that it does not interfere with the horizontal scrolling of the lists within).

    Regards,
    Deyan
    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.
  6. Stan
    Stan avatar
    38 posts
    Member since:
    May 2017

    Posted 17 Aug in reply to Deyan Link to this post

    Thanks!

    <ScrollView orientation="vertical">
            <GridLayout rows="30, 300, 30, 300, 30, 300" >

    Worked great.

  7. Stan
    Stan avatar
    38 posts
    Member since:
    May 2017

    Posted 06 Oct in reply to Nikolay Iliev Link to this post

    Follow-up problem with images not showing in Android:

    My following code all works as expected in iOS but not in Android. So I thought using the nativescript-fresco module would help but it does not and the fresco code is causing problems with iOS now.

    Please help. 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.BeerWine",
        "tns-ios": {
          "version": "3.1.0"
        },
        "tns-android": {
          "version": "3.1.1"
        }
      },
      "dependencies": {
        "nativescript-fresco": "^3.0.6",
        "nativescript-telerik-ui": "^3.0.4",
        "nativescript-theme-core": "~1.0.2",
        "tns-core-modules": "~3.1.0"
      },
      "devDependencies": {
        "babel-traverse": "6.25.0",
        "babel-types": "6.25.0",
        "babylon": "6.17.4",
        "lazy": "1.0.11"
      }
    }

    app.js

    require("./bundle-config");
    var application = require("application");
    var fresco = require("nativescript-fresco");
    if (application.android) {
            application.on("launch", function () {
            fresco.initialize();
        });
    }
    application.start({ moduleName: "main-page" });

    main-page.xml

    <Page xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:nfd="nativescript-fresco" xmlns:lv="nativescript-telerik-ui/listview" loaded="onPageLoaded">
        <ActionBar title="Liquor Store"/>

            <ScrollView orientation="vertical">
            <GridLayout rows="30, 200, 30, 200, 30, 200" >
                <Label row="0" text="Beers" height="30" style.backgroundColor="yellow" class="banner"/>
                <lv:RadListView row="1" id="beerList" items="{{ myBeerItems }}" selectionBehavior="Press" itemSelected="beerItemSelected">
                    <lv:RadListView.listViewLayout>
                        <lv:ListViewLinearLayout scrollDirection="Horizontal" itemHeight="200" itemWidth="200"/>
                    </lv:RadListView.listViewLayout>
                    <lv:RadListView.itemTemplate>
                        <StackLayout orientation="horizontal">
                            <nfd:FrescoDrawee width="200" height="200" loadMode="async" decodeWidth="200" decodeHeight="200" imageUri="{{ myBeers }}"/>
                        <!--    <Image id="beers" src="{{ myBeers }}" decodeWidth="200" decodeHeight="200" loadMode="async" height="200" width="200" />  -->
                        </StackLayout>
                    </lv:RadListView.itemTemplate>
                </lv:RadListView>

                <Label row="2" text="Wines" height="30" style.backgroundColor="yellow" class="banner"/>
                <lv:RadListView row="3" id="wineList" items="{{ myWineItems }}" selectionBehavior="Press" itemSelected="wineItemSelected">
                    <lv:RadListView.listViewLayout>
                        <lv:ListViewLinearLayout scrollDirection="Horizontal" itemHeight="200" itemWidth="200"/>
                    </lv:RadListView.listViewLayout>
                    <lv:RadListView.itemTemplate>
                        <StackLayout orientation="horizontal">
                            <Image id="wines" src="{{ myWines }}" decodeWidth="200" decodeHeight="200" loadMode="async" height="200" width="200" />
                        </StackLayout>
                    </lv:RadListView.itemTemplate>
                </lv:RadListView>

                <Label row="4" text="Whiskies" height="30" style.backgroundColor="yellow" class="banner"/>
                <lv:RadListView row="5" id="whiskyList" items="{{ myWhiskyItems }}" selectionBehavior="Press" itemSelected="whiskyItemSelected">
                    <lv:RadListView.listViewLayout>
                        <lv:ListViewLinearLayout scrollDirection="Horizontal" itemHeight="200" itemWidth="200"/>
                    </lv:RadListView.listViewLayout>
                    <lv:RadListView.itemTemplate>
                        <StackLayout orientation="horizontal">
                            <Image id="whisky" src="{{ myWhiskies }}" decodeWidth="200" decodeHeight="200" loadMode="async" height="200" width="200" />
                        </StackLayout>
                    </lv:RadListView.itemTemplate>
                </lv:RadListView>
            </GridLayout>
            </ScrollView>
    </Page>

    main-page.js

    var fs = require("file-system");
    var frameModule = require("ui/frame");
    var observable = require("data/observable");
    var ObservableArray = require("data/observable-array").ObservableArray;

    var myBeerImages = new ObservableArray();
    var myWineImages = new ObservableArray();
    var myWhiskyImages = new ObservableArray();
    var viewModel = new observable.Observable();
        viewModel.set("myBeerItems", myBeerImages);
        viewModel.set("myWineItems", myWineImages);
        viewModel.set("myWhiskyItems", myWhiskyImages);

    function readBeerFiles() {
        var beerDocuments = fs.knownFolders.currentApp();
        var myBeerFolder = beerDocuments.getFolder("beers");
        var beerArray = myBeerFolder.getEntitiesSync();
        myBeerImages = new ObservableArray();  // clear out array before reloading it
        beerArray.forEach(function (element) {
            myBeerImages.push({myBeers: element._path});
        });
        viewModel.set("myBeerItems", myBeerImages);  // reset viewModel with new array
    }

    function readWineFiles() {
        var wineDocuments = fs.knownFolders.currentApp();
        var myWineFolder = wineDocuments.getFolder("wines");
        var wineArray = myWineFolder.getEntitiesSync();
        myWineImages = new ObservableArray();  // clear out array before reloading it
        wineArray.forEach(function (element) {
            myWineImages.push({myWines: element._path});
        });
        viewModel.set("myWineItems", myWineImages);  // reset viewModel with new array
    }

    function readWhiskyFiles() {
        var whiskyDocuments = fs.knownFolders.currentApp();
        var myWhiskyFolder = whiskyDocuments.getFolder("whiskies");
        var whiskyArray = myWhiskyFolder.getEntitiesSync();
        myWhiskyImages = new ObservableArray();  // clear out array before reloading it
        whiskyArray.forEach(function (element) {
            myWhiskyImages.push({myWhiskies: element._path});
        });
        viewModel.set("myWhiskyItems", myWhiskyImages);  // reset viewModel with new array
    }

    exports.beerItemSelected = function(arg) {
        var selectedItem = myBeerImages.getItem(arg.index);
        var detailPic = selectedItem.myBeers
        frameModule.topmost().navigate({
            moduleName: "detail-page",
            bindingContext: {detailPic}
        });  
    }

    exports.wineItemSelected = function(arg) {
        var selectedItem = myWineImages.getItem(arg.index);
        var detailPic = selectedItem.myWines
        frameModule.topmost().navigate({
            moduleName: "detail-page",
            bindingContext: {detailPic}
        });  
    }

    exports.whiskyItemSelected = function(arg) {
        var selectedItem = myWhiskyImages.getItem(arg.index);
        var detailPic = selectedItem.myWhiskies
        frameModule.topmost().navigate({
            moduleName: "detail-page",
            bindingContext: {detailPic}
        });  
    }

    var beerList;
    var wineList;
    var whiskyList;
    exports.onPageLoaded = function(args) {
        readBeerFiles();
        readWineFiles();
        readWhiskyFiles();
        var page = args.object;
        beerList = page.getViewById("beerList");
        wineList = page.getViewById("wineList");
        whiskyList = page.getViewById("whiskyList");
        page.bindingContext = viewModel;
    }

    detail-page.xml

    <Page navigatingTo="onNavigatingTo">
        <ActionBar title="">
            <NavigationButton text="Go Back" />
        </ActionBar>    
        <Image src="{{ detailPic }}" stretch="aspectFill"/>
    </Page>

    detail-page.xml

    <Page navigatingTo="onNavigatingTo">
        <ActionBar title="">
            <NavigationButton text="Go Back" />
        </ActionBar>    
        <Image src="{{ detailPic }}" stretch="aspectFill"/>
    </Page>

    detail-page.js (not needed or used here)

  8. nikolay.tsonev
    Admin
    nikolay.tsonev avatar
    316 posts

    Posted 09 Oct Link to this post

    Hi Stan,

    Thank you for contacting us and for the attached sample code.

    I tested the code in a sample project, however, the images seem to be shown properly while using the default ImageView provided by the tns-core-modules and the latest version of nativescript-pro-ui 3.1.4 on Android simulator API level 25 and 23.

    For your convenience, I am attaching sample project and gif file from the simulator. Please review the sample project and make the needed changes, which will allow us to debug the problem on our side.

    In the meantime you could try upgrading the version of nativescript-pro-ui to 3.1.4, deleting node_modules and platforms folders and rebuilding the project.


    Regards,
    nikolay.tsonev
    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.
  9. Stan
    Stan avatar
    38 posts
    Member since:
    May 2017

    Posted 09 Oct in reply to nikolay.tsonev Link to this post

    Thank you so much for your project zip file.

    After some testing with different Android emulators and API levels, here is what I'm getting now. Please see attached.

    API level 25 is definitely better than 23, but there is still some very bad issues. It seems the breaking point is when there is about six images in each folders (categories) specially when the images are large files. 

    Thanks in advance.

  10. Answer
    nikolay.tsonev
    Admin
    nikolay.tsonev avatar
    316 posts

    Posted 10 Oct Link to this post

    Hello Stan,

    Thank you for the attached images, which shows the problem. 
    We investigated this case and found that this is something related to the native part of the application and it is not connected with the NativeScript abstraction.

    I found that some of the images provided in the sample app are large and they will be loaded properly on the latest API level, however, it will lead to an issue while showing it on the lower ones. This behavior with showing a blurred image or black one instead of the original is related to the fact that the image is too big for Android and it goes out of memory.  More about this topic could be found here in this StackOverflow thread.

    Regarding that, I would suggest resizing the images, which are set up in the application into a smaller size.


    Regards,
    nikolay.tsonev
    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.
Back to Top