Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
[Android] Use ScrollView inside SwipeView (#12819) fixes #12582
Browse files Browse the repository at this point in the history
* Added repro sample

* Fixed SwipeViewItem size

* Fix the issue
  • Loading branch information
jsuarezruiz committed Dec 10, 2020
1 parent 8fc193d commit ee7a5a6
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8" ?>
<local:TestContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:Xamarin.Forms.Controls"
mc:Ignorable="d"
Title="Test 12582"
x:Class="Xamarin.Forms.Controls.Issues.Issue12582">
<Grid
RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label
Padding="12"
BackgroundColor="Black"
TextColor="White"
Text="If can scroll the ScrollView inside the SwipeView, the test has passed."/>
<SwipeView
Grid.Row="1"
BackgroundColor="Transparent">
<SwipeView.TopItems>
<SwipeItems
Mode="Execute"
SwipeBehaviorOnInvoked="Close">
<SwipeItemView
HeightRequest="100">
<Grid
BackgroundColor="LawnGreen">
<Label
Text="Refresh"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center"/>
</Grid>
</SwipeItemView>
</SwipeItems>
</SwipeView.TopItems>
<SwipeView.Content>
<Grid
RowSpacing="0"
BackgroundColor="White">
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="60*"/>
<RowDefinition Height="30*"/>
</Grid.RowDefinitions>
<!--HEADER-->
<StackLayout
Grid.Row="0" Padding="20" BackgroundColor="Red">
<Label
Text="HEADER"
HorizontalOptions="Center"/>
</StackLayout>
<!--BODY-->
<ScrollView Grid.Row="1" BackgroundColor="Blue">
<StackLayout Spacing="20" Padding="15">
<Label Text="Dummy Text: 1" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 2" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 3" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 4" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 5" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 6" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 7" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 8" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 9" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 10" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 11" FontSize="Medium" Padding="12"/>
<Label Text="Dummy Text: 12" FontSize="Medium" Padding="12"/>
</StackLayout>
</ScrollView>
<!--FOOTER-->
<StackLayout
Grid.Row="2" Padding="20" BackgroundColor="Red">
<Label
Text="FOOTER"
HorizontalOptions="Center"/>
</StackLayout>
</Grid>
</SwipeView.Content>
</SwipeView>
</Grid>
</local:TestContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;

#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif

namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 12582,
"[Bug] ScrollView inside SwipeView",
PlatformAffected.Android)]
public partial class Issue12582 : TestContentPage
{
public Issue12582()
{
#if APP
InitializeComponent();
#endif
}

protected override void Init()
{

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1646,6 +1646,7 @@
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue12374.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12222.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12582.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12750.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12541.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue12574.cs" />
Expand Down Expand Up @@ -1987,6 +1988,9 @@
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue11081.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue12582.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue12750.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
Expand Down
111 changes: 98 additions & 13 deletions Xamarin.Forms.Platform.Android/Renderers/SwipeViewRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@
using Android.Content;
using Android.Graphics.Drawables;
using Android.Views;
using Android.Widget;
using AndroidX.AppCompat.Widget;
using AndroidX.Core.Widget;
using AndroidX.RecyclerView.Widget;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform.Android.AppCompat;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using AButton = AndroidX.AppCompat.Widget.AppCompatButton;
using APointF = Android.Graphics.PointF;
using ARect = Android.Graphics.Rect;
using ATextAlignment = Android.Views.TextAlignment;
using AView = Android.Views.View;
using AWebView = Android.Webkit.WebView;
using Specifics = Xamarin.Forms.PlatformConfiguration.AndroidSpecific.SwipeView;

namespace Xamarin.Forms.Platform.Android
Expand Down Expand Up @@ -241,9 +246,65 @@ bool ShouldInterceptTouch(MotionEvent e)
if (items == null || items.Count == 0)
return false;

return ShouldInterceptScrollChildrenTouch(swipeDirection);
}

bool ShouldInterceptScrollChildrenTouch(SwipeDirection swipeDirection)
{
if (!(_contentView is ViewGroup viewGroup))
return false;

int x = (int)(_initialPoint.X * _density);
int y = (int)(_initialPoint.Y * _density);

bool isHorizontal = swipeDirection == SwipeDirection.Left || swipeDirection == SwipeDirection.Right;

for (int i = 0; i < viewGroup.ChildCount; i++)
{
var child = viewGroup.GetChildAt(i);

if (IsViewInBounds(child, x, y))
{
if (child is AbsListView absListView)
return ShouldInterceptScrollChildrenTouch(absListView, isHorizontal);

if (child is RecyclerView recyclerView)
return ShouldInterceptScrollChildrenTouch(recyclerView, isHorizontal);

if (child is NestedScrollView scrollView)
return ShouldInterceptScrollChildrenTouch(scrollView, isHorizontal);

if (child is AWebView webView)
return ShouldInterceptScrollChildrenTouch(webView, isHorizontal);
}
}

return true;
}

bool ShouldInterceptScrollChildrenTouch(ViewGroup scrollView, bool isHorizontal)
{
AView scrollViewContent = scrollView.GetChildAt(0);

if (scrollViewContent != null)
{
if (isHorizontal)
return scrollView.ScrollX == 0 || scrollView.Width == scrollViewContent.Width + scrollView.PaddingLeft + scrollView.PaddingRight;
else
return scrollView.ScrollY == 0 || scrollView.Height == scrollViewContent.Height + scrollView.PaddingTop + scrollView.PaddingBottom;
}

return true;
}

bool IsViewInBounds(AView view, int x, int y)
{
ARect outRect = new ARect();
view.GetHitRect(outRect);

return x > outRect.Left && x < outRect.Right && y > outRect.Top && y < outRect.Bottom;
}

public override bool OnInterceptTouchEvent(MotionEvent e)
{
return ShouldInterceptTouch(e);
Expand Down Expand Up @@ -1145,32 +1206,56 @@ float GetSwipeThreshold(SwipeItems swipeItems)
swipeThreshold = GetSwipeItemHeight();
}
else
swipeThreshold = GetRevealModeSwipeThreshold();

return ValidateSwipeThreshold(swipeThreshold);
}

float GetRevealModeSwipeThreshold()
{
var swipeItems = GetSwipeItemsByDirection();
bool isHorizontal = IsHorizontalSwipe();

float swipeItemsSize = 0;
bool hasSwipeItemView = false;

foreach (var swipeItem in swipeItems)
{
if (isHorizontal)
swipeThreshold = CalculateSwipeThreshold();
else
if (swipeItem is SwipeItemView)
hasSwipeItemView = true;

if (swipeItem.IsVisible)
{
var contentHeight = (float)_context.FromPixels(_contentView.Height);
swipeThreshold = (SwipeThreshold > contentHeight) ? contentHeight : SwipeThreshold;
var swipeItemSize = GetSwipeItemSize(swipeItem);

if (isHorizontal)
swipeItemsSize += (float)swipeItemSize.Width;
else
swipeItemsSize += (float)swipeItemSize.Height;
}
}

return ValidateSwipeThreshold(swipeThreshold);
}
if (hasSwipeItemView)
{
var swipeItemsWidthSwipeThreshold = swipeItemsSize * 0.8f;

float CalculateSwipeThreshold()
{
if (_contentView != null)
return swipeItemsWidthSwipeThreshold;
}
else
{
var contentWidth = (float)_context.FromPixels(_contentView.Width);
var swipeThreshold = contentWidth * 0.8f;
if (_contentView != null)
{
var contentSize = isHorizontal ? _contentView.Width : _contentView.Height;
var contentSizeSwipeThreshold = contentSize * 0.8f;

return swipeThreshold;
return contentSizeSwipeThreshold;
}
}

return SwipeThreshold;
}


float ValidateSwipeThreshold(float swipeThreshold)
{
var contentHeight = (float)_context.FromPixels(_contentView.Height);
Expand Down
60 changes: 46 additions & 14 deletions Xamarin.Forms.Platform.iOS/Renderers/SwipeViewRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ void HandleTap()

void HandlePan(UIPanGestureRecognizer panGestureRecognizer)
{
if (panGestureRecognizer != null)
if (_isSwipeEnabled && panGestureRecognizer != null)
{
CGPoint point = panGestureRecognizer.LocationInView(this);
var navigationController = GetUINavigationController(GetViewController());
Expand Down Expand Up @@ -816,10 +816,18 @@ bool TouchInsideContent(double x1, double y1, double x2, double y2, double x, do
}

SwipeItems GetSwipeItemsByDirection()
{
if (_swipeDirection.HasValue)
return GetSwipeItemsByDirection(_swipeDirection.Value);

return null;
}

SwipeItems GetSwipeItemsByDirection(SwipeDirection swipeDirection)
{
SwipeItems swipeItems = null;

switch (_swipeDirection)
switch (swipeDirection)
{
case SwipeDirection.Left:
swipeItems = Element.RightItems;
Expand Down Expand Up @@ -1172,26 +1180,50 @@ void SwipeToThreshold(bool animated = true)
swipeThreshold = GetSwipeItemHeight();
}
else
swipeThreshold = GetRevealModeSwipeThreshold();

return ValidateSwipeThreshold(swipeThreshold);
}

double GetRevealModeSwipeThreshold()
{
var swipeItems = GetSwipeItemsByDirection();
bool isHorizontal = IsHorizontalSwipe();

float swipeItemsSize = 0;
bool hasSwipeItemView = false;

foreach (var swipeItem in swipeItems)
{
if (isHorizontal)
swipeThreshold = CalculateSwipeThreshold();
else
if (swipeItem is SwipeItemView)
hasSwipeItemView = true;

if (swipeItem.IsVisible)
{
var contentHeight = _contentView.Frame.Height;
swipeThreshold = (SwipeThreshold > contentHeight) ? contentHeight : SwipeThreshold;
var swipeItemSize = GetSwipeItemSize(swipeItem);

if (isHorizontal)
swipeItemsSize += (float)swipeItemSize.Width;
else
swipeItemsSize += (float)swipeItemSize.Height;
}
}

return ValidateSwipeThreshold(swipeThreshold);
}
if (hasSwipeItemView)
{
var swipeItemsWidthSwipeThreshold = swipeItemsSize * 0.8f;

double CalculateSwipeThreshold()
{
if (_contentView != null)
return swipeItemsWidthSwipeThreshold;
}
else
{
var swipeThreshold = _contentView.Frame.Width * 0.8;
if (_contentView != null)
{
var contentSize = isHorizontal ? _contentView.Frame.Width : _contentView.Frame.Height;
var contentSizeSwipeThreshold = contentSize * 0.8f;

return swipeThreshold;
return contentSizeSwipeThreshold;
}
}

return SwipeThreshold;
Expand Down

0 comments on commit ee7a5a6

Please sign in to comment.