[Android] fixes ListView pull-to-refresh gesture in non-data areas (#5417) fixes #5268

* [Android] fixes ListView pull-to-refresh gesture in non-data areas

* refactoring

* addressing comments
This commit is contained in:
Pavel Yakovlev 2019-06-06 06:55:17 -07:00 коммит произвёл Rui Marinho
Родитель 6644b8fd24
Коммит 2fddd083e9
4 изменённых файлов: 134 добавлений и 2 удалений

Просмотреть файл

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Controls.Issues.Issue5268">
<ListView x:Name="MyListView"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
ItemsSource="{Binding Sources}"
BackgroundColor="Blue"
RefreshCommand="{Binding Command}" RowHeight="100">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ScrollView>
<StackLayout>
<Label Text="{Binding Val}" MaxLines="100" HorizontalTextAlignment="Center" TextColor="White" FontSize="14" />
<Label Text="{Binding Val}" MaxLines="100" HorizontalTextAlignment="Center" TextColor="White" FontSize="14" />
<Label Text="{Binding Val}" MaxLines="100" HorizontalTextAlignment="Center" TextColor="White" FontSize="14" />
<Label Text="{Binding Val}" MaxLines="100" HorizontalTextAlignment="Center" TextColor="White" FontSize="14" />
<Label Text="{Binding Val}" MaxLines="100" HorizontalTextAlignment="Center" TextColor="White" FontSize="14" />
</StackLayout>
</ScrollView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>

Просмотреть файл

@ -0,0 +1,42 @@
#if APP
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 5268, "ListView with PullToRefresh enabled gestures conflict", PlatformAffected.Android)]
public partial class Issue5268 : ContentPage
{
[Preserve(AllMembers = true)]
public class SrcItem
{
public string Val { get; set; }
}
string GenerateLongString() => string.Join(" \n", Enumerable.Range(0, 50).Select(i => $"{Sources.Count} item"));
public ObservableCollection<SrcItem> Sources { get; }
public ICommand Command { get; }
public Issue5268()
{
InitializeComponent();
Sources = new ObservableCollection<SrcItem>();
Command = new Command(AddData);
Sources.Add(new SrcItem { Val = GenerateLongString() });
MyListView.BindingContext = this;
}
void AddData()
{
IsBusy = true;
Sources.Add(new SrcItem { Val = GenerateLongString() });
IsBusy = false;
}
}
}
#endif

Просмотреть файл

@ -434,6 +434,10 @@
<DependentUpon>Issue5003.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue5268.xaml.cs">
<DependentUpon>Issue5268.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)LegacyComponents\NonAppCompatSwitch.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MapsModalCrash.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ModalActivityIndicatorTest.cs" />
@ -1119,4 +1123,10 @@
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue5268.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>

Просмотреть файл

@ -9,6 +9,7 @@ using Xamarin.Forms.Internals;
using System;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Android.Widget;
using Android.Runtime;
namespace Xamarin.Forms.Platform.Android
{
@ -102,6 +103,9 @@ namespace Xamarin.Forms.Platform.Android
return new Size(40, 40);
}
protected virtual SwipeRefreshLayout CreateNativePullToRefresh(Context context)
=> new SwipeRefreshLayoutWithFixedNestedScrolling(context);
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
@ -154,9 +158,9 @@ namespace Xamarin.Forms.Platform.Android
nativeListView = CreateNativeControl();
if (Forms.IsLollipopOrNewer)
nativeListView.NestedScrollingEnabled = true;
_refresh = new SwipeRefreshLayout(ctx);
_refresh = CreateNativePullToRefresh(ctx);
_refresh.SetOnRefreshListener(this);
_refresh.AddView(nativeListView, LayoutParams.MatchParent);
_refresh.AddView(nativeListView, new LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent));
SetNativeControl(nativeListView, _refresh);
_headerView = new Container(ctx);
@ -523,5 +527,54 @@ namespace Xamarin.Forms.Platform.Android
SetMeasuredDimension(widthSpec, heightSpec);
}
}
class SwipeRefreshLayoutWithFixedNestedScrolling : SwipeRefreshLayout
{
float _touchSlop;
float _initialDownY;
bool _nestedScrollAccepted;
bool _nestedScrollCalled;
public SwipeRefreshLayoutWithFixedNestedScrolling(Context ctx) : base(ctx)
{
_touchSlop = ViewConfiguration.Get(ctx).ScaledTouchSlop;
}
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
if (ev.Action == MotionEventActions.Down)
_initialDownY = ev.GetAxisValue(Axis.Y);
var isBeingDragged = base.OnInterceptTouchEvent(ev);
if (!isBeingDragged && ev.Action == MotionEventActions.Move && _nestedScrollAccepted && !_nestedScrollCalled)
{
var y = ev.GetAxisValue(Axis.Y);
var dy = (y - _initialDownY) / 2;
isBeingDragged = dy > _touchSlop;
}
return isBeingDragged;
}
public override void OnNestedScrollAccepted(AView child, AView target, [GeneratedEnum] ScrollAxis axes)
{
base.OnNestedScrollAccepted(child, target, axes);
_nestedScrollAccepted = true;
_nestedScrollCalled = false;
}
public override void OnStopNestedScroll(AView child)
{
base.OnStopNestedScroll(child);
_nestedScrollAccepted = false;
}
public override void OnNestedScroll(AView target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)
{
base.OnNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
_nestedScrollCalled = true;
}
}
}
}