Making a Container


#1

Hi,
I’m trying to design a pop-up class, as in something is tapped, and then a list pops up from the bottom. Similar to the regular iOS menu, here’s an example:

When the green button is tapped a menu appears. I want to class with an empty menu, where I can set the title, and the description. It should also be a container, so I can fill the stack panel with any items I want.

Here’s my attempt, it’s not great:

<Container ux:Class="OptionsPanel" Subtree="innerPanel" HitTestMode="LocalBoundsAndChildren" Title="Title" Description="Description" Open="false">
	<bool ux:Property="Open" />
	<string ux:Property="Title" />
	<string ux:Property="Description" />
	<WhileTrue Value="{Property this.Open}">
		<Set OptionsControlPanel.Active="main" />
	</WhileTrue>
	<WhileFalse Value="{Property this.Open}">
		<Set OptionsControlPanel.Active="away" />
	</WhileFalse>
	<PageControl ux:Binding="Children" ux:Name="OptionsControlPanel" Orientation="Vertical" Active="away">
		<Page ux:Binding="Children" ux:Name="main" Margin="8" Alignment="Bottom">
			<ActivatingAnimation>
				<Change backRect.Opacity="0.5" Duration="0.3" Delay="0.3" />
			</ActivatingAnimation>
			<DockPanel ux:Binding="Children">
				<StackPanel Dock="Top" Padding="32, 32, 32, 0">
					<Text Value="{Property this.Title}" Font="Subtitle" FontSize="15" Color="{Resource DarkBlue}" />
					<Text Value="{Property this.Description}" Font="Regular" FontSize="15" Opacity="0.6" TextWrapping="Wrap" />
					<Rectangle Height="1" Color="#000" Opacity="0.1" Margin="0, 8, 0, 0" />
				</StackPanel>
				<ScrollView ux:Binding="Children" SnapMinTransform="false">
					<StackPanel ux:Name="innerPanel">
						
					</StackPanel>
				</ScrollView>
				<Panel ux:Binding="Children" Dock="Bottom" Height="52">
					<Text Width="52" Alignment="Center" TextAlignment="Center" TextColor="#FFF" Value="&#xF12C;" Font="MaterialIcon" FontSize="24" />
					<Rectangle CornerRadius="0, 0, 4, 4" Color="{Resource Highlight}" Opacity="0.5" />
					<Clicked>
						<Callback Handler="{save}" />
					</Clicked>
				</Panel>
			</DockPanel>
			<Rectangle CornerRadius="4" Color="#FFF" />
		</Page>
		<Page>
			<WhileActive>
				<Change this.HitTestMode="None" />
			</WhileActive>
		</Page>
	</PageControl>
	<Rectangle ux:Name="backRect" Color="#000" Opacity="0" />
</Container>

Here’s a fully working example with terrible colours:

<App>
	
	<Panel ux:Name="DaysPanel" HitTestMode="LocalBoundsAndChildren">
		<PageControl ux:Name="DaysPanelControl" Orientation="Vertical" Active="away">
			<Page ux:Name="away">
				<WhileActive>
					<Change DaysPanel.HitTestMode="None" />
				</WhileActive>
			</Page>
			<Page ux:Name="main" Margin="8" Alignment="Bottom">
				<ActivatingAnimation>
					<Change backRect.Opacity="0.5" Duration="0.3" Delay="0.3" />
				</ActivatingAnimation>
				<DockPanel>
					<StackPanel Dock="Top" Padding="32, 32, 32, 0">
						<Text Value="Workout Days" FontSize="15" Color="#00f" />
						<Text Value="Your workouts will cycle through your selected days." FontSize="15" Opacity="0.6" TextWrapping="Wrap" />
						<Rectangle Height="1" Color="#000" Opacity="0.1" Margin="0, 8, 0, 0" />
					</StackPanel>
					<ScrollView SnapMinTransform="false">
						<StackPanel>
							<Each Count="7">
								<Panel HitTestMode="LocalBoundsAndChildren" Height="52" Padding="32, 0, 32, 0" >
									<Text Value="Test" Opacity="0.8" Alignment="CenterLeft" />
								</Panel>
							</Each>
						</StackPanel>
					</ScrollView>
					<Panel Dock="Bottom" Height="52">
						<Text Width="52" Alignment="Center" TextAlignment="Center" TextColor="#FFF" Value="&#xF12C;" FontSize="24" />
						<Rectangle CornerRadius="0, 0, 4, 4" Color="#0f0" Opacity="0.5" />
						<Clicked>
							<Set DaysPanelControl.Active="away" />
						</Clicked>
					</Panel>
				</DockPanel>
				<Rectangle CornerRadius="4" Color="#FFF" />
			</Page>
		</PageControl>
		<Rectangle ux:Name="backRect" Color="#000" Opacity="0" >
			<Clicked>
				<Set DaysPanelControl.Active="away" />
			</Clicked>
		</Rectangle>
	</Panel>
	<Button Text="Click me" Alignment="Center">
		<Clicked>
			<Set DaysPanelControl.Active="main" />
		</Clicked>
	</Button>
</App>

Essentially this is a vertical PageControl with the entire panel being placed on a very high level in the page. When the main page isn’t active then it has no hitbox. Also, I want to be able to choose the “done” function, in my attempt I leave it at {save} because I’m not sure how to do this. I feel like I’ve approached this all the wrong way, any advice would be great!

Cheers


#2

The designer of the app I am developing came with a solution for something similar of that you want to do. For us this is just a picker in a list but this can be changed to suit your needs.

<Panel>
   <!-- ComboBox Button -->
   <Panel ux:Class="ComboBoxBtn" HitTestMode="LocalBounds">
      <bool ux:Property="HasValue"/>
      <string ux:Property="Placeholder"/>

      <DockPanel Offset="0,8">
         <Each Count="1" TemplateSource="this" TemplateKey="Option">
            <DockPanel Padding="15,0,15,20">
               <Icon Value="&#xE5CF;" FontSize="20" Color="color2" Dock="Right" Alignment="Bottom"/>
               <Medium ux:Name="label" Value="{Property this.Placeholder}" FontSize="14" TextColor="gray2" Alignment="Bottom" TextAlignment="Left" Dock="Fill" />
               <WhileTrue Value="{Property this.HasValue}">
                  <Change label.Color="color2" />
               </WhileTrue>
            </DockPanel>
         </Each>
      </DockPanel>
      <WhilePressed>
         <Change this.Color="#eee"/>
      </WhilePressed>
      <!-- <Rectangle Color="color2" Height="1" Alignment="Bottom"/> -->
   </Panel>

   <!-- ComboBox -->
   <Panel ux:Class="ComboBox">
      <object ux:Property="Options"/>
      <object ux:Property="Selected"/>
      <bool ux:Property="IsOpen"/>

      <JavaScript>
        var Observable = require ("FuseJS/Observable");

        var self = this;
        var options = self.Options.inner();

        module.exports = {
           options : options.map(function(option){
              return {
                 title : option.name,
                 value : option.val,
                 isSelected : Observable(function() { return self.Selected.value.value.val == option.val; }),
                 clicked : function () {
                   if (self.Selected.value instanceof Observable) {
                     self.Selected.value.value = option;
                   }
                 }
              }
           })
        }
      </JavaScript>

      <!-- Dropdown -->
      <StackPanel ux:Name="dropdown" Padding="12" Color="gray1" >
        <IconButton.Action Icon="{icons.close}" IconColor="gray2" IconSize="26" Alignment="TopRight">
          <Clicked>
             <Set this.IsOpen="false" />
          </Clicked>
        </IconButton.Action>
         <ScrollView>
            <StackPanel Width="90%">
               <Each Items="{options}">
                  <Panel ux:Name="item" Height="40" HitTestMode="LocalBounds">
                     <Medium ux:Name="title" Value="{title}" Color="gray2" TextAlignment="Center" Alignment="Center"/>
                     <WhileTrue Value="{isSelected}">
                       <Change title.Color="color2"/>
                     </WhileTrue>
                     <WhilePressed>
                        <Change item.Color="gray1b"/>
                     </WhilePressed>
                     <Clicked Handler="{clicked}" >
                        <Set this.IsOpen="false" />
                     </Clicked>
                     <!-- <Rectangle Color="white" Height="1" Alignment="Bottom"/> -->
                  </Panel>
               </Each>
            </StackPanel>
         </ScrollView>
         <WhileFalse Value="{Property this.IsOpen}">
            <Change dropdown.Opacity="0" Duration="0.2" Easing="CubicOut" />
            <Change dropdown.Visibility="Hidden" Delay="0.2" />
         </WhileFalse>
      </StackPanel>
   </Panel>
</Panel>

and this is how we call the class

<ComboBoxBtn HasValue="{hasCountry}" Placeholder="{selectedCountry.name}" >
	<Clicked>
			<Set Combobox.Options="{countryOptions}" />
			<Set Combobox.Selected="{selectedCountry}" />
			<Set Combobox.IsOpen="true" />
	</Clicked>

	<Rectangle Color="color2" Height="1" Alignment="Bottom"/>
</ComboBoxBtn>

in the JS

var hasCountry = Observable(false);
var countryOptions =Observable({name:"Country1", val: 1}, {name:"Country2", val: 2});
var selectedCountry = Observable({name : "Country", val :null});
selectedCountry.onValueChanged(module, function (sel) {
  if (sel.val != null)
    hasCountry.value = true;
});

Ours solution does not have a animation as yours example but I hope that this is what you were looking for. Sorry If I did not understand what you asked.


#3

Thanks Wilton, great share, though this isn’t what I want.


#4

Hi Fahad.

In this case i would just use a WhileTrue to show/hide the popup panel instead of a PageControl.
You can give it the proper animation using AddingAnimation and RemovingAnimation.

I’ve modified your example to use my suggested method. Let me know if there is something that needs explaining :):

<App>
	<Panel ux:Class="Popup">
		<bool ux:Property="Show"/>
		<WhileTrue ux:Name="showDaysPanel" Value="{Property Show}">
			<Panel ux:Name="DaysPanel" HitTestMode="LocalBoundsAndChildren" Color="White">

				<AddingAnimation>
					<Move Y="1" RelativeTo="Size" Duration="0.3" />
					<Change backRect.Opacity="0.5" Duration="0.3" Delay="0.3" />
				</AddingAnimation>
				<RemovingAnimation>
					<Move Y="1" RelativeTo="Size" Duration="0.3" />
					<Change backRect.Opacity="0.5" Duration="0.3" Delay="0.3" />
				</RemovingAnimation>
				<DockPanel>
					<StackPanel Dock="Top" Padding="32, 32, 32, 0">
						<Text Value="Workout Days" FontSize="15" Color="#00f" />
						<Text Value="Your workouts will cycle through your selected days." FontSize="15" Opacity="0.6" TextWrapping="Wrap" />
						<Rectangle Height="1" Color="#000" Opacity="0.1" Margin="0, 8, 0, 0" />
					</StackPanel>
					<ScrollView SnapMinTransform="false">
						<StackPanel>
							<Each Count="7">
								<Panel HitTestMode="LocalBoundsAndChildren" Height="52" Padding="32, 0, 32, 0" >
									<Text Value="Test" Opacity="0.8" Alignment="CenterLeft" />
								</Panel>
							</Each>
						</StackPanel>
					</ScrollView>
					<Panel Dock="Bottom" Height="52">
						<Text Width="52" Alignment="Center" TextAlignment="Center" TextColor="#FFF" Value="&#xF12C;" FontSize="24" />
						<Rectangle CornerRadius="0, 0, 4, 4" Color="#0f0" Opacity="0.5" />
						<Clicked>
							<Toggle Target="showDaysPanel"/>
						</Clicked>
					</Panel>
				</DockPanel>

				
				<Rectangle ux:Name="backRect" Color="#000" Opacity="0" >
					<Clicked>
						<Toggle Target="showDaysPanel"/>
					</Clicked>
				</Rectangle>
			</Panel>
		</WhileTrue>
	</Panel>
	<Popup ux:Name="popup"/>
    <Button Text="Click me" Alignment="Center">
        <Clicked>
			<Set popup.Show="true" />
        </Clicked>
    </Button>
</App>


#5

Hi,

Sorry to reply so late, there is a problem with using a bool instead of a PageControl. First, swiping isn’t available.

Secondly, the example you posted is not a Container, which means I can’t add in items when using the new made component.

Finally, there is a lag between tapping the button and the panel appearing, this is the biggest issue, I’m not sure what’s causing it.

Thanks!


#6

Hi!

You can get swiping to work using the SwipeGesture behavior:
https://www.fusetools.com/docs/fuse/gestures/swipegesture

The delay was a problem with my AddingAnimation. Simply add DelayBack="0" on the Move and it works as expected.

<AddingAnimation>
	<Move Y="1" RelativeTo="Size" Duration="0.3" DelayBack="0"/>
	<Change backRect.Opacity="0.5" Duration="0.3" Delay="0.3" />
</AddingAnimation>

As for it not being a container, thats not very hard to fix, just change the base type of the class to a Container and hook up its children as explained in the Container documentation:
https://www.fusetools.com/docs/fuse/controls/container

Here is the fixed code:

<App>
    <Container ux:Class="Popup" Subtree="content">
		<Panel ux:Binding="Children">
			<bool ux:Property="Show"/>



			<SwipingAnimation Source="swipe">
				<Change trans.Y="0"/>
			</SwipingAnimation>

			<WhileSwiping Source="swipe">
				<DebugAction Message="swiping" />
			</WhileSwiping>

			<Panel ux:Name="daysPanel" HitTestMode="LocalBoundsAndChildren" Color="White">
				<Translation ux:Name="trans" Y="1" RelativeTo="Size" />

				<AddingAnimation>
					<Move Y="1" RelativeTo="Size" Duration="0.3" DelayBack="0"/>
					<Change backRect.Opacity="0.5" Duration="0.3" Delay="0.3" />
				</AddingAnimation>
				<RemovingAnimation>
					<Move Y="1" RelativeTo="Size" Duration="0.3" />
					<Change backRect.Opacity="0.5" Duration="0.3" Delay="0.3" />
				</RemovingAnimation>
				<DockPanel>
					<StackPanel Dock="Top" Padding="32, 32, 32, 0">
						<Text Value="Workout Days" FontSize="15" Color="#00f" />
						<Text Value="Your workouts will cycle through your selected days." FontSize="15" Opacity="0.6" TextWrapping="Wrap" />
						<Rectangle Height="1" Color="#000" Opacity="0.1" Margin="0, 8, 0, 0" />
					</StackPanel>
					<ScrollView SnapMinTransform="false">
						<StackPanel>
							<Each Count="7">
								<Panel HitTestMode="LocalBoundsAndChildren" Height="52" Padding="32, 0, 32, 0" >
									<Text Value="Test" Opacity="0.8" Alignment="CenterLeft" />
								</Panel>
							</Each>
						</StackPanel>
					</ScrollView>
					<Panel Dock="Bottom" Height="52">
						<Text Width="52" Alignment="Center" TextAlignment="Center" TextColor="#FFF" Value="&#xF12C;" FontSize="24" />
						<Rectangle CornerRadius="0, 0, 4, 4" Color="#0f0" Opacity="0.5" />
						<Clicked>
							<Set swipe.IsActive="false" />
						</Clicked>
					</Panel>
				</DockPanel>


				<Rectangle ux:Name="backRect" Color="#000" Opacity="0" >

				</Rectangle>
			</Panel>

			<Panel ux:Name="content" HitTestMode="LocalBoundsAndChildren">
				<SwipeGesture ux:Name="swipe" Direction="Up" LengthNode="content" Type="Active"/> 
			</Panel>
			

		</Panel> 
	</Container>

	
    <Popup ux:Name="popup">
		<Panel Color="#d50000">
			<StackPanel Alignment="Center">
				<Text Value="This is our content" FontSize="35" Alignment="HorizontalCenter"/>
				<Text Value="Swipe up" FontSize="30" Alignment="HorizontalCenter"/>
			</StackPanel>
		</Panel>
	</Popup>

</App>

#7

Thanks for your reply.

I’ve put together code from this thread to create the almost perfect component:

<App>
    <Container Subtree="innerPanel" HitTestMode="None" ux:Class="Popup">
        <bool ux:Property="Show" />
        <Panel ux:Binding="Children" ux:Name="content" Padding="8" Alignment="Bottom">
            <SwipeGesture ux:Name="swipe" LengthNode="content" Direction="Down" />
            <Swiped Source="swipe">
                <Toggle Target="showDaysPanel" /> 
            </Swiped>
            <SwipingAnimation Source="swipe">
                <Move Y="1" RelativeTo="Size" /> 
            </SwipingAnimation>
            <Translation ux:Name="trans" Y="1" RelativeTo="Size" />
            <DockPanel ux:Binding="Children">
                <StackPanel ux:Binding="Children" Dock="Top" Padding="32, 32, 32, 0">
                    <Text ux:Binding="Children" Value="Workout Days" FontSize="15" Color="#00f" />
                    <Text ux:Binding="Children" Value="Your workouts will cycle through your selected days." FontSize="15" Opacity="0.6" TextWrapping="Wrap" />
                    <Rectangle ux:Binding="Children" Height="1" Color="#000" Opacity="0.1" Margin="0, 8, 0, 0" /> 
                </StackPanel>
                <ScrollView ux:Binding="Children" SnapMinTransform="false">
                    <StackPanel ux:Name="innerPanel" /> 
                </ScrollView>
                <Panel ux:Binding="Children" Dock="Bottom" Height="52">
                    <Clicked>
                        <Toggle Target="showDaysPanel" /> 
                    </Clicked>
                    <Text ux:Binding="Children" Width="52" Alignment="Center" TextAlignment="Center" TextColor="#FFF" Value="&#xF12C;" FontSize="24" />
                    <Rectangle ux:Binding="Children" CornerRadius="0, 0, 4, 4" Color="#0f0" Opacity="0.5" /> 
                </Panel>
            </DockPanel>
            <Rectangle ux:Binding="Children" CornerRadius="4" Color="#FFF" /> 
        </Panel>
        <Rectangle ux:Binding="Children" ux:Name="backRect" Color="#000" Opacity="0">
            <Clicked>
                <Toggle Target="showDaysPanel" /> 
            </Clicked>
        </Rectangle>
        <WhileTrue ux:Name="showDaysPanel" Value="{Property Show}">
            <Move Target="content" Y="-1" RelativeTo="Size" Duration="0.4" Easing="CircularInOut" />
            <Change backRect.Opacity="0.5" Duration="0.4" />
            <Change this.HitTestMode="LocalBoundsAndChildren" /> 
        </WhileTrue>
    </Container>
    <Popup ux:Name="popup">
        <Each Count="3">
            <Panel Background="White" HitTestMode="LocalBoundsAndChildren" Height="52" Padding="32, 0, 32, 0">
                <Text Value="Test" Opacity="0.8" Alignment="CenterLeft" /> 
            </Panel>
        </Each>
    </Popup>
    <Button Text="Click me" Alignment="Center">
        <Clicked>
            <Set popup.Show="true" /> 
        </Clicked>
    </Button>
</App>

The issues here are:

  • swiping down causes the animation to play twice
  • “Click me” only works once, because I can’t internally toggle the “Show” bool

EDIT: This was fixed by Uldis, <Set this.Show="false" /> can be used (duh). Thanks a lot! As for the double-animation, it can be fixed (again by Uldis) using ToggleSwipeActive for all of the animations (toggling between the Active/Inactive state of the Swipe for all animations).

Thank you both for your help