WP7应用开发笔记(11) 自定义按钮
不知不觉写了很多东西,不过结构有点乱了,写完了需要整理一下。回顾一下界面设计,这草图又要出来献丑了。
除了已经实现的圆形触控控件以外,其他按钮都是圆环+图片的方式,有比较有写一个自定义控件,取个名字叫RoundButton。
RoundButton类
RoundButton具有和Button相同的行为和视觉状态,唯一区别是RoundButton拥有图标
那么继承Button并添加依赖属性ImageSource类型为ImageSource。
再添加一个ImageBrush用于绘制图片。
代码如下:
public class RoundButton : Button
{
protected ImageBrush OpacityImageBrush;
private const string OpacityImageBrushName = "OpacityImageBrush";
public RoundButton()
{
DefaultStyleKey = typeof(RoundButton);
}
public readonly DependencyProperty ImageSourceProperty
= DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(RoundButton), new PropertyMetadata(OnImageSourceChanged));
private static void OnImageSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var sender = o as RoundButton;
if (sender == null || e.NewValue == e.OldValue)
return;
sender.SetImageBrush(e.NewValue as ImageSource);
}
public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
OpacityImageBrush = GetTemplateChild(OpacityImageBrushName) as ImageBrush;
if (ImageSource == null)
ImageSource = new BitmapImage(new Uri("/VirtualKeyboard.Controls;component/Icons/word.ok.png", UriKind.RelativeOrAbsolute));
else
SetImageBrush(ImageSource);
}
private void SetImageBrush(ImageSource imageSource)
{
if (OpacityImageBrush == null)
return;
OpacityImageBrush.ImageSource = imageSource;
}
}
RoundButton模板
编写好RoundButton类后还需要编写其模板已呈现出圆形按钮的效果
基本模板由两个重叠的圆Ellipse构成:
<StackPanel>
<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Margin="3">
<Ellipse
x:Name="ButtonBackground"
Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="{StaticResource PhoneStrokeThickness}"
Fill="{TemplateBinding Background}"
Margin="{StaticResource PhoneTouchTargetOverhang}" />
<Ellipse
x:Name="ButtonForeground"
Fill="{TemplateBinding Foreground}"
Margin="{StaticResource PhoneTouchTargetOverhang}">
<Ellipse.OpacityMask>
<ImageBrush x:Name="OpacityImageBrush" />
</Ellipse.OpacityMask>
</Ellipse>
</Grid>
</StackPanel>
呈现如下:
为了对输入响应我需要按下的视觉状态VisualState Pressed 通过VisualStateGroups添加相应的动画板Storyboard实现
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneContrastBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneContrastBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="ButtonForeground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
呈现效果:
完整XAML代码
View Code
<Style TargetType="local:RoundButton">
<Setter Property="BorderBrush" Value="{StaticResource PhoneContrastBackgroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/>
<Setter Property="FontSize" Value="12" />
<Setter Property="Padding" Value="10,3,10,5"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:RoundButton">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneContrastBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Stroke" Storyboard.TargetName="ButtonBackground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneContrastBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="ButtonForeground">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel>
<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Margin="3">
<Ellipse
x:Name="ButtonBackground"
Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="{StaticResource PhoneStrokeThickness}"
Fill="{TemplateBinding Background}"
Margin="{StaticResource PhoneTouchTargetOverhang}" />
<Ellipse
x:Name="ButtonForeground"
Fill="{TemplateBinding Foreground}"
Margin="{StaticResource PhoneTouchTargetOverhang}">
<Ellipse.OpacityMask>
<ImageBrush x:Name="OpacityImageBrush" />
</Ellipse.OpacityMask>
</Ellipse>
</Grid>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
完成播放器界面布局
有了按钮,我还PS了一套图标,将RoundButton设置好布局后效果如下,是不是有点感觉了。