I need to reproduce this behavior with Xamarin Forms
Can someone help me with my problem? I have the task to reproduce the above example in Xamarin Forms, a flexible and dismissible UI form for enter data with MVVM, I need help to achieve this. I will appreciate your collaboration.
CodePudding user response:
I would suggest looking at this:
https://github.com/sthewissen/Xamarin.Forms.PancakeView
You could then use a TapGestureRecognizer (https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/gestures/tap) on the PancakeView to programmatically animate its height, have a look at this (it's for the BoxView but the code should be similar):
To achieve the example you provided, just add a ListView inside the PancakeView and bind it to your data - I guess you know how to do that, since you mentioned you know how to implement MVVM.
CodePudding user response:
Formatting and style aside, I would suggest that you should look at gesture recognisers to move the list of countries.
- If the user must drag the list up then you could look at using a PanGestureRecognizer .
- If the user is to swipe up, triggering an animation movement of the list then look at SwipeGestureRecognizer and maybe TranslateTo animation
CodePudding user response:
You could use a frame to simulate the bottom sheet in your screenshot. You could check the code below.
<RelativeLayout>
<StackLayout Padding="10,20,0,0">
<Label Text="Page7" />
</StackLayout>
<Frame
x:Name="bottomSheet"
Padding="1,4,1,0"
BackgroundColor="#faf9f8"
CornerRadius="8"
HasShadow="true"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1,
Constant=0}"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=1,
Constant=0}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=.9,
Constant=0}">
<Frame.GestureRecognizers>
<PanGestureRecognizer PanUpdated="OnPanUpdated" />
</Frame.GestureRecognizers>
<StackLayout Spacing="5">
<BoxView
BackgroundColor="Gray"
CornerRadius="2"
HeightRequest="5"
HorizontalOptions="Center"
WidthRequest="50" />
<SearchBar
x:Name="SearchBox"
BackgroundColor="Transparent"
Focused="SearchBar_Focused"
Placeholder="Search by Ingredient"
/>
<StackLayout x:Name="GridFilter">
<Button />
</StackLayout>
</StackLayout>
</Frame>
</RelativeLayout>
Code behind:
public Page7()
{
InitializeComponent();
}
public double getProportionCoordinate(double proportion)
{
return proportion * Height;
}
private void SearchBar_Focused(object sender, FocusEventArgs e)
{
GridFilter.IsVisible = true;
openBottomSheet();
}
void openBottomSheet()
{
var finalTranslation = Math.Max(Math.Min(0, -1000), -Math.Abs(getProportionCoordinate(.85)));
bottomSheet.TranslateTo(bottomSheet.X, finalTranslation, 150, Easing.SpringIn);
}
// Important Code Lives Below
double x, y;
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
// Handle the pan
switch (e.StatusType)
{
case GestureStatus.Running:
// Translate and ensure we don't y e.TotalY pan beyond the wrapped user interface element bounds.
var translateY = Math.Max(Math.Min(0, y e.TotalY), -Math.Abs((Height * .25) - Height));
bottomSheet.TranslateTo(bottomSheet.X, translateY, 20);
break;
case GestureStatus.Completed:
// Store the translation applied during the pan
y = bottomSheet.TranslationY;
//at the end of the event - snap to the closest location
var finalTranslation = Math.Max(Math.Min(0, -1000), -Math.Abs(getClosestLockState(e.TotalY y)));
//depending on Swipe Up or Down - change the snapping animation
if (isSwipeUp(e))
{
bottomSheet.TranslateTo(bottomSheet.X, finalTranslation, 250, Easing.SpringIn);
}
else
{
bottomSheet.TranslateTo(bottomSheet.X, finalTranslation, 250, Easing.SpringOut);
}
//dismiss the keyboard after a transition
SearchBox.Unfocus();
y = bottomSheet.TranslationY;
break;
}
}
public bool isSwipeUp(PanUpdatedEventArgs e)
{
if (e.TotalY < 0)
{
return true;
}
return false;
}
//TO-DO: Make this cleaner
public double getClosestLockState(double TranslationY)
{
//Play with these values to adjust the locking motions - this will change depending on the amount of content ona apge
var lockStates = new double[] { 0, .5, .85 };
//get the current proportion of the sheet in relation to the screen
var distance = Math.Abs(TranslationY);
var currentProportion = distance / Height;
//calculate which lockstate it's the closest to
var smallestDistance = 10000.0;
var closestIndex = 0;
for (var i = 0; i < lockStates.Length; i )
{
var state = lockStates[i];
var absoluteDistance = Math.Abs(state - currentProportion);
if (absoluteDistance < smallestDistance)
{
smallestDistance = absoluteDistance;
closestIndex = i;
}
}
var selectedLockState = lockStates[closestIndex];
var TranslateToLockState = getProportionCoordinate(selectedLockState);
return TranslateToLockState;
}
For more details of the data binding, you could refer to the MS docs. https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/