-
-
Save sushihangover/565d2daedb4d98adceb577588719dd29 to your computer and use it in GitHub Desktop.
A custom ListView for Xamarin.Android that enables scrolling via moving a DragShadow to the top or bottom.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// File: XamarinScrollableListView.cs | |
// Created: 27.07.2016 | |
// | |
// This class represents a custom View. It inherits from ListView but adds automatic Drag and Drop scrolling. | |
using Android.Content; | |
using Android.Runtime; | |
using Android.Util; | |
using Android.Views; | |
using Android.Widget; | |
using Java.Lang; | |
namespace yournamespace | |
{ | |
[Register("your.package.name.here.yournamespace.XamarinScrollableListView")] | |
public sealed class XamarinScrollableListView : ListView | |
{ | |
private bool isScrolling; | |
private float lastY; | |
private int scrollBy; | |
public XamarinScrollableListView(Context context, IAttributeSet attrs) : base(context, attrs) | |
{ | |
this.Drag += this.OnDrag; | |
this.SetOnScrollListener(new OnScrollListener(this)); | |
} | |
private void OnDrag(object sender, DragEventArgs args) | |
{ | |
if (args.Event.Action == DragAction.Location) | |
{ | |
this.lastY = args.Event.GetY(); | |
this.ScrollUpdate(this.lastY); | |
} | |
else if (args.Event.Action == DragAction.Ended) | |
{ | |
this.isScrolling = false; | |
} | |
} | |
private void ScrollUpdate(float y) | |
{ | |
var height = this.Height; | |
var scrollBorder = height/3; | |
var position = (int) y; | |
this.scrollBy = 0; | |
if (position < scrollBorder) | |
{ | |
this.scrollBy = -(scrollBorder - position); | |
} | |
else if (position > height - scrollBorder) | |
{ | |
this.scrollBy = position - (height - scrollBorder); | |
} | |
if (this.scrollBy == 0) | |
{ | |
this.isScrolling = false; | |
return; | |
} | |
// Math incoming: A quadratic function with some division eases to smooth out scroll speed | |
this.scrollBy = (int) (Math.Pow(this.scrollBy/7d, 2)/(scrollBorder/10d))*(this.scrollBy < 0 ? -1 : 1); | |
if (this.isScrolling) | |
{ | |
this.SmoothScrollBy(this.scrollBy, 0); | |
} | |
this.isScrolling = true; | |
} | |
private class OnScrollListener : Object, IOnScrollListener | |
{ | |
private readonly XamarinScrollableListView super; | |
private int prevFirstVisibleItem; | |
private int prevLastVisibleItem; | |
public OnScrollListener(XamarinScrollableListView super) | |
{ | |
this.super = super; | |
} | |
public void OnScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) | |
{ | |
var lastVisibleItem = firstVisibleItem + visibleItemCount - 1; | |
View child = null; | |
if (firstVisibleItem != this.prevFirstVisibleItem) | |
{ | |
child = this.super.GetChildAt(0); | |
} | |
if (this.prevLastVisibleItem != lastVisibleItem) | |
{ | |
child = this.super.GetChildAt(this.super.ChildCount - 1); | |
} | |
if (child != null) | |
{ | |
// Workaround to set newly scrolled items as valid drop targets | |
child.Visibility = ViewStates.Invisible; | |
child.Visibility = ViewStates.Visible; | |
} | |
this.prevLastVisibleItem = lastVisibleItem; | |
this.prevFirstVisibleItem = firstVisibleItem; | |
} | |
public void OnScrollStateChanged(AbsListView view, ScrollState scrollState) | |
{ | |
if (this.super.isScrolling) | |
{ | |
this.super.SmoothScrollBy(this.super.scrollBy, 0); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment