zoukankan      html  css  js  c++  java
  • 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设置好布局后效果如下,是不是有点感觉了。

  • 相关阅读:
    【React Native】某个页面禁用物理返回键
    【React Native】DeviceEventEmitter监听通知及带参数传值
    转载【React Native代码】手写验证码倒计时组件
    【React Native】 中设置 APP 名称、应用图标、为安卓添加启动图
    【React Native错误集】* What went wrong: Execution failed for task ':app:installDebug'.
    【React Native错误集】Import fails with "Failed to execute 'ImportScripts' on 'WorkerGlobalScope'"
    【React Native错误集】Android error “Could not get BatchedBridge, make sure your bundle is packaged properly” on start of app
    「React Native笔记」在React的 setState 中操作数组和对象的多种方法(合集)
    【React Native】Error: Attribute application@allowBackup value=(false) from AndroidManifest.xml
    坚果云如何使用二次验证码/谷歌身份验证器/两步验证/虚拟MFA?
  • 原文地址:https://www.cnblogs.com/kiminozo/p/2329621.html
Copyright © 2011-2022 走看看