--- /dev/null
+<?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>
\ No newline at end of file
--- /dev/null
+#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
\ No newline at end of file
<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" />
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue5268.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </EmbeddedResource>
+ </ItemGroup>
</Project>
\ No newline at end of file
using System;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Android.Widget;
+using Android.Runtime;
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();
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);
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;
+ }
+ }
}
}