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

[Enhancement] AdaptiveTriggers #9422

Merged
merged 28 commits into from
Feb 7, 2020
Merged

[Enhancement] AdaptiveTriggers #9422

merged 28 commits into from
Feb 7, 2020

Conversation

jsuarezruiz
Copy link
Contributor

@jsuarezruiz jsuarezruiz commented Feb 4, 2020

Description of Change

An AdaptiveTrigger provides an easy way to set the threshold (also called 'breakpoint') where a state is applied. A VisualState defines property values that are applied to an element when it’s in a particular state. You group visual states in a VisualStateManager that applies the appropriate VisualState when the specified conditions are met.

Example:

<VisualStateGroupList>
        <VisualStateGroup>
            <VisualState x:Name="Narrow">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="0" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Property="BackgroundColor" Value="Blue" />
            </VisualState.Setters>
        </VisualState>
        <VisualState x:Name="Wide">
            <VisualState.StateTriggers>
                <AdaptiveTrigger MinWindowWidth="1000" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Property="BackgroundColor" Value="Green" />
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>
</VisualStateGroupList>

Issues Resolved

API Changes

Added:

public class StateTriggerBase
{
    public void SetActive(bool active);
    public bool IsActive { get; }
}

public class AdaptiveTrigger : StateTriggerBase
{
    public double MinHeight { get; set; }
    public double MinWidth { get; set; }
}

public class OrientationStateTrigger : StateTriggerBase
{
    public DeviceOrientation Orientation { get; set; }
}

public class DeviceStateTrigger : StateTriggerBase
{
    public string Device { get; set; }
}

public class CompareStateTrigger : StateTriggerBase
{
    public object Property { get; set; }
    public object Value { get; set; }
}

In Xamarin.Forms.DualScreen:

public class DualScreenSpanModeStateTrigger : StateTriggerBase
{
    public TwoPaneViewMode SpanMode { get; set; }
}

Platforms Affected

  • Core/XAML (all platforms)
  • iOS
  • Android
  • UWP

Behavioral/Visual Changes

None

Before/After Screenshots

AdaptiveTrigger
adaptivetrigger2

DeviceStateTrigger

<VisualStateGroupList>
    <VisualStateGroup>
        <VisualState
            x:Name="Android">
            <VisualState.StateTriggers>
                <DeviceStateTrigger Device="Android" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Property="BackgroundColor" Value="Blue" />
            </VisualState.Setters>
        </VisualState>
        <VisualState
            x:Name="iOS">
            <VisualState.StateTriggers>
                <DeviceStateTrigger Device="iOS" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Property="BackgroundColor" Value="Red" />
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>
</VisualStateGroupList>

Running on Android
devicestate-droid

Running on iOS
devicestate-ios

OrientationStateTrigger

<VisualStateGroupList>
        <VisualStateGroup>
        <VisualState
            x:Name="Landscape">
            <VisualState.StateTriggers>
                <OrientationStateTrigger Orientation="Landscape" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Property="BackgroundColor" Value="Blue" />
            </VisualState.Setters>
        </VisualState>
        <VisualState
            x:Name="Portrait">
            <VisualState.StateTriggers>
                <OrientationStateTrigger Orientation="Portrait" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Property="BackgroundColor" Value="Red" />
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>
</VisualStateGroupList>

orientationtrigger

CompareStateTrigger

<VisualStateGroupList>
    <VisualStateGroup>
        <VisualState x:Name="Wide">
            <VisualState.StateTriggers>
                <CompareStateTrigger Property="{Binding IsChecked, Source={x:Reference CheckBox}}" Value="True" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Property="BackgroundColor" Value="Green" />
            </VisualState.Setters>
        </VisualState>
        <VisualState x:Name="Narrow">
            <VisualState.StateTriggers>
                <CompareStateTrigger Property="{Binding IsChecked, Source={x:Reference CheckBox}}" Value="False" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Property="BackgroundColor" Value="Red" />
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>
</VisualStateGroupList>

comparestatetrigger

DualScreenStateTrigger

<Grid>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="Normal">
                <VisualState.StateTriggers>
                    <dualScreen:DualScreenSpanModeStateTrigger SpanMode="SinglePane"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Property="BackgroundColor" Value="Red" />
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="Spanned">
                <VisualState.StateTriggers>
                    <dualScreen:DualScreenSpanModeStateTrigger SpanMode="Wide" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Property="BackgroundColor" Value="Green" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

one-screen

two-screens

Testing Procedure

Launch Core Gallery and navigate to the VisualStateManager samples. Here, can find new samples related with Adaptive Triggers.

PR Checklist

  • Targets the correct branch
  • Tests are passing (or failures are unrelated)

@PureWeen PureWeen requested review from hartez and PureWeen and removed request for StephaneDelcroix February 5, 2020 05:26
Xamarin.Forms.Core/AdaptiveTrigger.cs Outdated Show resolved Hide resolved
{
var weakEvent = new WeakEventListener<OrientationStateTrigger, object, EventArgs>(this)
{
OnEventAction = (instance, source, eventArgs) => OnSizeChanged(source, eventArgs),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DeviceInfo implements INPC so you can just subscribe to that and watch for Orientation changes

Copy link
Contributor

@PureWeen PureWeen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some Core.UnitTests as well?

@jsuarezruiz jsuarezruiz removed the DO-NOT-MERGE-!!! 🛑 This is in progress and needs to be updated before it can be merged. label Feb 5, 2020
@jsuarezruiz
Copy link
Contributor Author

@PureWeen I have added some unit tests.

Xamarin.Forms.Core/View.cs Outdated Show resolved Hide resolved
@PureWeen PureWeen mentioned this pull request Feb 5, 2020
2 tasks
@jsuarezruiz jsuarezruiz changed the base branch from master to 4.5.0 February 6, 2020 09:00
@jsuarezruiz jsuarezruiz changed the title AdaptiveTriggers [Enhancement] AdaptiveTriggers Feb 6, 2020
@dotMorten
Copy link
Contributor

Thank you for making IsActive a public getter instead of protected. I'd like to propose you also add an event for when it changes. The reason for that is to be able to make composite state triggers. I state my case for that in this design issue:
microsoft/microsoft-ui-xaml#1460

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
5 participants