Настало время перейти к одной из самых важных частей 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 , оба с изображениями внутри. Эти кнопки не имеют границ и подсвечиваются при нажатии.
Ваш пользовательский интерфейс теперь должен выглядеть примерно так:
Поздравляем! Теперь у вас есть пользовательский интерфейс, обычно готовый для основного рабочего экрана.