Настало время перейти к одной из самых важных частей MangoTree — базовому интерфейсу, который будет использоваться для отображения следующих данных одним касанием:
- График
- Упоминания
- DMs
- ретвитов
- Поисковые
Это пять основных возможностей, которые должны быть размещены в пяти отдельных разделах. Вопрос — какой контроль использовать? Мы могли бы пойти в метро и воспользоваться панорамой или панелью управления. Это было бы хорошо, но в этом случае будет избыточное пойло (например , получение от временной шкалы к зеркалам потребуются , по крайней мере , два пойла). Мы также могли бы создать список на главной странице, чем уже занимаются такие клиенты Twitter, как Beezz . Это неудобно, потому что это потребует от пользователя постоянно перемещаться между различными страницами, чтобы попасть в нужный раздел.
В конце — я решил использовать TabControl . Официально он не поддерживается в Windows Phone, но, тем не менее, работает, так как является основным компонентом Silverlight.
TabControl? Но это не Метро!
Используйте то, что лучше для текущей ситуации. Вам нравится Панорама или Пивот ? Не стесняйтесь реализовать это таким образом. С точки зрения удобства использования, TabControl является лучшим выбором для этого случая . Это на самом деле не такая уж большая проблема, как это делают другие люди .
Шаг 1: Добавьте правильную ссылку на пространство имен и измененный стиль
Я надеюсь, что после прочтения предыдущей статьи из этой серии вы уже ознакомились со статьей, которую я написал об использовании TabControl в приложении для Windows Phone. Если нет, пожалуйста, перейдите туда сначала .
Я назвал свой стиль MetroTabItem и поместил его в файл App.xaml . Затем я приступил к созданию TabControl как части основной рабочей сетки в WorkPage.xaml .
Ваш код объявления TabControl должен выглядеть следующим образом:
<cc:TabControl Background="Transparent">
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 1" Foreground="Black"></cc:TabItem>
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 2" Foreground="Black"></cc:TabItem>
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 3" Foreground="Black"></cc:TabItem>
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 4" Foreground="Black"></cc:TabItem>
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 5" Foreground="Black"></cc:TabItem>
</cc:TabControl>
Убедитесь , что вы установили Фоновую свойство для TabControl в прозрачный , поэтому мы не будем иметь дело с белым фоном (набор по умолчанию).
Теперь ваш главный экран должен выглядеть примерно так:
Я отредактировал стиль по умолчанию, поэтому он работает в соответствии с выбранной в данный момент темой Windows Phone — если я узнал кое-что о приложениях, использующих фиксированные цвета, то это то, что иногда они не работают достаточно хорошо, когда пользователь решает переключить тема от темного (по умолчанию) до светлого, особенно если в самом приложении разработчик смешал статические цвета с зависимыми от темы.
Вот модифицированный XAML:
<Style x:Key="MetroTabItem" TargetType="cc:TabItem">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Background" Value="{StaticResource PhoneBackgroundBrush}"/>
<Setter Property="BorderBrush" Value="#FFA3AEB9"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="6,2,6,2"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="MinWidth" Value="5"/>
<Setter Property="MinHeight" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="cc:TabItem">
<Grid x:Name="Root">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
<VisualTransition GeneratedDuration="0:0:0.1" To="MouseOver"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimationUsingKeyFrames BeginTime="0" Duration="00:00:00.001" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="FocusVisualTop">
<SplineDoubleKeyFrame KeyTime="0" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualTopSelected">
<SplineDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="DisabledVisualTopUnSelected">
<SplineDoubleKeyFrame KeyTime="0" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualTop">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualElement">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="TemplateTopSelected" Visibility="Collapsed" Canvas.ZIndex="1">
<Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="1,1,1,0" Background="{StaticResource PhoneForegroundBrush}" CornerRadius="3,3,0,0" Margin="-2,-2,-2,0">
<Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="1" CornerRadius="1,1,0,0">
<Grid>
<Rectangle Fill="{StaticResource PhoneBackgroundBrush }" Margin="0,0,0,-2"/>
<ContentControl x:Name="HeaderTopSelected" Cursor="{TemplateBinding Cursor}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
</Grid>
</Border>
</Border>
<Border x:Name="FocusVisualTop" BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="1,1,1,0" CornerRadius="3,3,0,0" IsHitTestVisible="false" Margin="-2,-2,-2,0" Visibility="Collapsed"/>
<Border x:Name="DisabledVisualTopSelected" Background="{StaticResource PhoneDisabledBrush}" CornerRadius="3,3,0,0" IsHitTestVisible="false" Margin="-2,-2,-2,0" Opacity="0"/>
</Grid>
<Grid x:Name="TemplateTopUnselected" Visibility="Collapsed">
<Border x:Name="BorderTop" BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="1" Background="{StaticResource PhoneDisabledBrush}" CornerRadius="3,3,0,0">
<Grid>
<ContentControl x:Name="HeaderTopUnselected" Cursor="{TemplateBinding Cursor}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" IsTabStop="False" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalAlignment}"/>
</Grid>
</Border>
<Border x:Name="DisabledVisualTopUnSelected" Background="{StaticResource PhoneDisabledBrush}" CornerRadius="3,3,0,0" IsHitTestVisible="false" Opacity="0"/>
</Grid>
<Border x:Name="FocusVisualElement" BorderBrush="White" BorderThickness="1" CornerRadius="3,3,0,0" IsHitTestVisible="false" Margin="-1" Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Если вам нужна ссылка на существующие кисти и цвета, пожалуйста, прочитайте эту статью . Теперь вы можете легко сравнить, что мы сделали:
Выглядит намного лучше — над этим еще предстоит поработать, но мы добираемся.
Шаг 2: Установите заголовки TabItem
Следующим шагом будет правильная маркировка заголовков TabItem , чтобы мы знали, что связано с каждым из них. Также нам, вероятно, понадобятся иконки. Я использовал значки из Templarian , добавив белый штрих для совместимости тем, и я в итоге установил шаблон заголовка для каждого TabItem :
<cc:TabControl Background="Transparent">
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 1">
<cc:TabItem.HeaderTemplate>
<DataTemplate>
<Image Source="/Images/appbar.timeline.png"></Image>
</DataTemplate>
</cc:TabItem.HeaderTemplate>
</cc:TabItem>
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 2">
<cc:TabItem.HeaderTemplate>
<DataTemplate>
<Image Source="/Images/appbar.mentions.png"></Image>
</DataTemplate>
</cc:TabItem.HeaderTemplate>
</cc:TabItem>
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 3">
<cc:TabItem.HeaderTemplate>
<DataTemplate>
<Image Source="/Images/appbar.message.png"></Image>
</DataTemplate>
</cc:TabItem.HeaderTemplate>
</cc:TabItem>
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 4">
<cc:TabItem.HeaderTemplate>
<DataTemplate>
<Image Source="/Images/appbar.repeat.png"></Image>
</DataTemplate>
</cc:TabItem.HeaderTemplate>
</cc:TabItem>
<cc:TabItem Style="{StaticResource MetroTabItem}" Height="80" Width="89" Header="Tab 5">
<cc:TabItem.HeaderTemplate>
<DataTemplate>
<Image Source="/Images/appbar.magnify.png"></Image>
</DataTemplate>
</cc:TabItem.HeaderTemplate>
</cc:TabItem>
</cc:TabControl>
Вот что вы в конечном итоге получите:
Приложение, наконец, приобретает нужную форму. Пришло время разработать собственный TextBox, который будет использоваться для публикации обновления пользователя.
Шаг 3: Подготовьте элемент управления вводом «обновление состояния»
Он будет помещен в пространство, занимаемое в настоящее время заголовком страницы. Это будет большой элемент управления с двумя дополнительными кнопками — Загрузить изображение и Опубликовать обновление . Очевидно, я не буду нести ярлыки, а скорее картинки, которые представляют их.
Я использую обычный элемент управления TextBox с прикрепленным к нему пользовательским стилем.
<TextBox MaxLength="140" TextWrapping="Wrap" Height="140" Style="{StaticResource StatusTextBox}"></TextBox>
Счетчик символов отсутствует, поэтому может показаться, что пользователь может невольно превысить ограничение в 140 символов на твит. Чтобы избежать этого, я вручную устанавливаю свойство MaxLength для TextBox .
Стиль определяется так:
<Style x:Key="StatusTextBox" TargetType="TextBox">
<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilyNormal}"/>
<Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/>
<Setter Property="Background" Value="{StaticResource PhoneTextBoxBrush}"/>
<Setter Property="Foreground" Value="{StaticResource PhoneTextBoxForegroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource PhoneTextBoxBrush}"/>
<Setter Property="SelectionBackground" Value="{StaticResource PhoneAccentBrush}"/>
<Setter Property="SelectionForeground" Value="{StaticResource PhoneTextBoxSelectionForegroundBrush}"/>
<Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/>
<Setter Property="Padding" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DisabledOrReadonlyBorder">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="ReadOnly">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="EnabledBorder">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="DisabledOrReadonlyBorder">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="DisabledOrReadonlyBorder">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="DisabledOrReadonlyBorder">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="DisabledOrReadonlyContent">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxReadOnlyBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="EnabledBorder">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="EnabledBorder">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneTextBoxEditBorderBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="EnabledBorder" Background="{TemplateBinding Background}" Margin="{StaticResource PhoneTouchTargetOverhang}">
<Grid>
<ContentControl x:Name="ContentElement" BorderThickness="0" HorizontalContentAlignment="Stretch" Margin="8,2,68,2" Padding="{TemplateBinding Padding}" VerticalContentAlignment="Stretch">
</ContentControl>
<Button x:Name="StatusImage" Opacity=".6" Height="64" HorizontalAlignment="Right" VerticalAlignment="Top" Padding="0" BorderThickness="0">
<Image Height="64" Source="Images/appbar.right.png" Stretch="Fill" Width="64" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>
<Button x:Name="PhotoImage" Opacity=".6" Height="64" HorizontalAlignment="Right" VerticalAlignment="Bottom" Padding="0" BorderThickness="0">
<Image Height="64" Source="Images/appbar.camera.png" Stretch="Fill" Width="64" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Обратите внимание, что в конце у меня объявлены два экземпляра Button , оба с изображениями внутри. Эти кнопки не имеют границ и подсвечиваются при нажатии.
Ваш пользовательский интерфейс теперь должен выглядеть примерно так:
Поздравляем! Теперь у вас есть пользовательский интерфейс, обычно готовый для основного рабочего экрана.