This is a migrated thread and some comments may be shown as answers.

Snap to item

16 Answers 186 Views
ListView
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
John
Top achievements
Rank 1
John asked on 18 Jun 2017, 12:10 PM

Hello,

I have set up a ListView for Android with a LinearLayout scrolling horizontally. Each item takes up the complete width of the screen.

Now, whenever the user finishes scrolling, I'd like the item to be smoothly centered in the ListView just like an image slider.

I suppose for iOS setting "scrollPosition" to "ListViewScrollPosition.CenteredHorizontally" would exactly get me the result, I'm looking for.

But how do I implement this behaviour for Android?

 

Greetings,

John

16 Answers, 1 is accepted

Sort by
0
Nick Iliev
Telerik team
answered on 19 Jun 2017, 07:44 AM
Hi John Miller,

Thank you for contacting us and for your interest in nativescript-telerik-ui plugins.
Indeed at this very moment, there is no option to scrollToPosition by pixels on Android,
The only scrolling opportunity at this moment is to scrollByIndex where you can pass the index of your item.

The good news is that our developer's team is already planning this feature. For you convenience, I have opened this feature request issue where you can track the updated info on that matter (the issue is a linked to the internal developer's side issue). Once we have a stable solution we will update the info and the release notes for RadListView and also the article for scrollTo Position as well.

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.
0
John
Top achievements
Rank 1
answered on 19 Jun 2017, 11:01 AM

Hi Nikolay,

Thanks for your reply and opening an issue for me. Happy to hear the feature is already planned.

So just to clarify, this feature would also include the following behaviour:
After releasing 'scroll' the list item would move automatically to the desired position, like ListViewScrollPosition for iOS?

And one more point. I tested scrollToIndex(). Just in case I missed it in the documentation: There is no way to have a smooth transition, is there? Using this function it directly jumps to the index.

Regards,
John

0
Accepted
Nick Iliev
Telerik team
answered on 19 Jun 2017, 01:19 PM
Hello John,

The actual implementation will depend on multiple factors including selecting the most stable and reversible solution. I would suggest appending your question to the opened issue where the developers would be able to look at it and decide if that is doable functionality.

Regarding the question about smooth scroll on Android
There is a solution that will allow you to create smooth scrolling for Android; However, the first thing I want to underline that the solution is using private properties (usually with names starting with underscore _) which can not be considered as stable workaround for future upcoming releases (all private properties and methods can be changed or removed in future releases). That said here is the solution:

You will need to get reference to your list
e.g.
let list;
 
export function onPageLoaded(args) {
    let page = args.object;
    list = <RadListView>(page.getViewById("listView"));
 
    page.bindingContext = new viewModel.ViewModel();
}

And from there you can access the private Android implementation with _android on which you can access the method smoothScrollToPosition
export function makeSmoothScroll() {
    list._android.smoothScrollToPosition(5);
}


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.
0
John
Top achievements
Rank 1
answered on 19 Jun 2017, 02:48 PM

Hi Nikolay,

Thanks for your help. Smooth scrolling works like a charm. I'll keep the risk with private members and future updates in mind.

Regarding my other question: I posted it on GitHub as suggested.

Regards,
John

0
Deyan
Telerik team
answered on 19 Jun 2017, 02:58 PM
Hi John,

Thanks for writing.

The upcoming NS UI 3.0 release will contain API for smooth-scrolling to a given position and by a given amount of pixels. The snapping feature is something we need more time to implement and thus will postpone it for the next (post-June) iteration. You will still be able to implement it on your side by calculating the amount of pixels to scroll by to center a given item though.

Please do not hesitate to write back in case you have further questions or need assistance.

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.
0
John
Top achievements
Rank 1
answered on 05 Jul 2017, 10:25 AM

Hello,
I waited for the 3.0 Release and switched from the private member _android to the new function scrollToIndex(index, true) and got it all up and running as desired.

I have two remaining questions though. My setup is roughly as follows:

The html:

<RadListView #listView (itemLoading)="onItemLoading($event)" (scrollEnded)="onScrollEnded($event)" [items]="itemData">
    <ListViewLinearLayout tkListViewLayout scrollDirection="Horizontal"></ListViewLinearLayout>
    <ng-template tkListTemplate let-itemData="item">
        <GridLayout rows="*,*,*,*,*" columns="*,*,*,*,*">
            <StackLayout *ngFor="let firstFieldItem of itemData.firstField; let i = index"
                                    [row]="(i / 5) | trunc" [col]="i % 5">
                <Label [text]="firstFieldItem"></Label>
            </Stacklayout>
        </GridLayout>
        <GridLayout rows="*,*,*,*,*" columns="*,*,*,*,*">
            <StackLayout *ngFor="let secondFieldItem of itemData.secondField; let i = index"
                                    [row]="(i / 5) | trunc" [col]="i % 5">
                <Label [text]="secondFieldItem"></Label>
            </Stacklayout>
        </GridLayout>
        <GridLayout rows="*,*,*,*,*" columns="*,*,*,*,*">
            <StackLayout *ngFor="let thirdFieldItem of itemData.thirdField; let i = index"
                                    [row]="(i / 5) | trunc" [col]="i % 5">
                <Label [text]="thirdFieldItem"></Label>
            </Stacklayout>
        </GridLayout>
    </ng-template>
</RadListView>

The typescript:

export class MyListViewComponent {
    @ViewChild("listView) listViewComponent: RadListViewComponent;
    private screenWidth: number = screen.mainScreen.widthDIPs;
    protected itemData: Array...
 
    protected onItemLoading(event: ListViewEventData) {
        event.view.width = this.screenWidth;
    }
 
    protected onScrollEnded(event: ListViewScrollEventData) {
        currentListItem = Math.round(event.scrollOffset / this.screenWidth);
        this.listViewComponent.listView.scrollToIndex(currentListItem , true);
    }
}

 

So my questions are:
1. Instead of waiting for the scrolling to end before I manually scroll to an index, I'd like to already do that as soon as the mouse/finger goes up, thus only scrolling to the next/previous item. I just couldn't find a hook for it. Because currently when I do a really quick swipe, it fastly scrolls to the end of the list.

2. My current setup with three nested GridLayout with ngFor-loops inside takes some time to initialize and stutters on the first pass. Is there a way to optimize it for performance?

Regards,
John

0
Deyan
Telerik team
answered on 05 Jul 2017, 12:32 PM
Hi John,

Thanks for writing back. Good to hear that the new APIs are working.

1. We will need to further extend the scrolling events to notify you when the drag gesture has ended. This will be added in the TODO list but there's no an adequate way to do this as of now.

2. Can you please elaborate a bit further what your exact scenario with the template is? If you have a predefined number of rows and columns (5) you may simply create them all at once in your template and bind multiple labels to the separate items from the array on your business object without using ngFor loops.

Let us know should you have additional questions.

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.
0
John
Top achievements
Rank 1
answered on 19 Jul 2017, 09:17 AM

Hello,

thank you for your help and sorry I couldn't reply any sooner.

About my questions from above:

1. Ok, so there is no "dragEnded" event yet. Alternativly is it possible to adjust the scrolling speed? In my case scrolling at a much slower pace would already help.

2. The number of items is indeed predefined. I got rid of the ngFor-Loops and hardcoded all the labels. This did improve the performance to some amount.
I'll try to describe the scenario in more detail. After the changes the GridLayouts inside the RadListView look like:

<GridLayout rows="*,*,*,*,*" columns="*,*,*,*,*">
    <StackLayout row="0" col="0" (tap)="onTap("1") [class.selected]="isSelected("1")>
        <Label text="1"></Label>
    </StackLayout>
    <StackLayout row="0" col="1" (tap)="onTap("2") [class.selected]="isSelected("2")>
        <Label text="2"></Label>
    </StackLayout>
 
    ...
 
</GridLayout>

I put every Label inside its own StackLayout to center the text vertically; the fields have no absolute height. Maybe there is a better way? The result looks like in the attachment.
So with a StackLayout and two event listeners per Label there is perhaps some overhead which could be handled better?

Anyway, as soon as I have scrolled for the first time, the template is preloaded and moves fluently. But it takes some time to initialize and stutters when i drag for the first time. Is there a way to optimize the preloading?

 

Regards,
John

0
Deyan
Telerik team
answered on 20 Jul 2017, 11:51 AM
Hello John,

Thanks for writing back.

1. I am happy to inform you that we've just added the scrollDragEnded event on RadListView which is fired each time the user raises their finger off the device's screen as a result of a scrolling gesture. You will be able to access the new API in a day or two when the nativescript-telerik-ui-pro@next and nativescript-telerik-ui@next versions are updated on npmjs.com. This new API will also make it into the next official version of the plugin.

2. Just thinking about the case, I cannot immediately propose a solution that will improve the performance. It might help if you are able to attach your project here so that we can directly take a look and see how we can help.

Thanks for your time.

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.
0
Deyan
Telerik team
answered on 20 Jul 2017, 03:22 PM
Hello John,

On a side-note, we have prepared a very thorough blogpost on the performance of NativeScript apps and the different approaches to finding bottlenecks:

https://www.nativescript.org/blog/deep-dive-into-nativescript-3.1-performance-improvements

There are several tools you might find useful in determining the reasons for various performance issues.

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.
0
John
Top achievements
Rank 1
answered on 20 Jul 2017, 03:53 PM

Hello Deyan,

those are great news! Both, the next  release and the blogpost. I'll have a thorough read, thanks.

I will attach the project as soon as I finish to create a trimmed-down version.

Regards,
John

0
John
Top achievements
Rank 1
answered on 15 Aug 2017, 06:13 PM
Hello Deyan,

I created a basic version of my app just consisting of the page containing the list view and a service to manage some data.
You can find it here: https://github.com/JohnMller/performance-test

As described earlier, I use the list view as some kind of image slider which you can drag sideways.
On each slide you can select up to five numbers, deselect them, fill it randomly or clear it.

The issue is that the list view stutters when dragging the slides to the side. This occurs after the page is initialized. As soon as the list items are cached it runs more smoothly.
When you navigate to another page ('next' button) and back again the list items have to be cached again.

Kind regards,
John
0
Deyan
Telerik team
answered on 16 Aug 2017, 01:03 PM
Hi John,

Thanks for writing back.

I have reviewed the behaviour mentioned by you and have managed to reproduce the unacceptable scrolling experience up until views are properly cached. Unfortunately this scenario would bring performance degradation even if you implemented it using native Android, i.e. without NativeScript and Angular on top. To improve this scenario a bit of custom coding would be required. 

One possible option would be to implement a custom component that visualises these numbers in a grid without using elements like Labels and StackLayouts. This will improve the performance since the layout system will be excluded from the equation. Moreover, creation of the Labels and StackLayouts will also not happen. You will simply have one element that will receive size and will manually draw the cells and the numbers. It will also react to the user input and will change the state of the selected cells. This will be quite fast. This will also require native iOS and Android development but is not a complicated task to do. You will be able to easily reuse this native component in your NativeScript app then.

Another possible option would be to use a component that we plan to expose in NativeScript UI - a TabView which may also work as a SlideView, i.e. without showing tabs and allowing for browsing through items by sliding a finger on each of them. This is on our TODO list for the next couple of months.

I have also tried to reduce the amount of visual elements within your item template to improve performance although no considerable results were achieved - see the attached file for details. It might give you some direction how to optimize further.

I hope this is helpful.

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.
0
John
Top achievements
Rank 1
answered on 17 Aug 2017, 10:47 AM

Hi Deyan,

could you please elaborate your suggestion to implement a custom component a little bit? Just a pointer to some examples to get the idea, since I haven't developed native Android/iOS so far.

By the way, I'm really happy with the new scrollDragEnded event. It does improve the handling quite a bit.

Is it possible to enable/disable scrolling for the ListView?

Thank you,
Regards,
John

0
Deyan
Telerik team
answered on 18 Aug 2017, 07:53 AM
Hi John,

Of course.

My point was to implement a custom Android View and wrap it in a NativeScript View which can be used in your XML that represents the List template. Instead of using tens of StackLayout and Label instances, you can simply draw them without building a complex hierarchy. Here's the official Google documentation on drawing in a View:

https://developer.android.com/training/custom-views/custom-drawing.html

You may also find this article useful:

http://www.vogella.com/tutorials/AndroidCustomViews/article.html

This should not take much time to implement and the Java APIs for Android are quite straightforward.

I hope this is helpful.

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.
0
Deyan
Telerik team
answered on 18 Aug 2017, 08:12 AM
Hi John,

I have just noticed that I missed your last question:

Currently it is not possible to block the scrolling in RadListView. We will put this on our TODO list for implementation.

Here's a useful link on how to integrate a native Android library for usage in NativeScript: https://docs.nativescript.org/runtimes/android/plugins/plugins#directory-structure

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.
Tags
ListView
Asked by
John
Top achievements
Rank 1
Answers by
Nick Iliev
Telerik team
John
Top achievements
Rank 1
Deyan
Telerik team
Share this question
or