Home > Software design >  How can I create a Xamarin Forms UI window like the attached image?
How can I create a Xamarin Forms UI window like the attached image?

Time:09-17

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):

https://social.msdn.microsoft.com/Forums/en-US/d936d5c5-2320-40aa-88cd-06e691604dca/animating-height-of-box-view?forum=xamarinforms

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.

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/

  • Related