[UWP]从头开始创建并发布一个番茄钟

1. 自己用的番茄钟自己做

在PC上我一直使用“小番茄”作为我的番茄钟软件,我把它打开后放在副显示器最大化,这样不仅可以让它尽到本分,而且还可以告诉我的同事“我正在专心工作”。可是我总是嫌弃它的手感不够愉悦,总想自己写一个番茄钟软件,正好最近很久没写UWP应用了很手痒,于是就抽空写了个自用的番茄钟并发布到微软应用商店。

结果手感也并不愉悦。

另外,本来本来我也打算用Storyboard实现动画,但火火总是劝我不要搞Storyboard,要用Composition API做动画。Storyboard的能力是有极限的,我从短暂的UWP生涯当中学到一件事,人越是玩弄动画,动画就越可能因为没有料到的事态而失败……除非超越Storyboard。所以我也不做Sotryboard啦。

微软的应用商店是一个还不错的平台,WPF程序员可以基于现有的知识轻易地创建一个UWP应用并发布到应用商店。尤其是现在微软的审核比较宽松,只要是对得起自己良心的应用一般都能通过审核。虽然因为商店抽风我自己都很难下载到自己的应用。这篇文章将讲解从创建UWP项目到发布到商店的整个流程。

2. 需求

我只想要一个可以倒计时的Timer,顺便玩玩UWP的新API,所以原则上越简单越好,然后想到什么做什么。

很多番茄钟软件都会提供任务列表功能,还可以通过图表展示番茄数量、完成任务数量的统计。不过我已经有To-Do和Azure Devops,平时的工作还会记录在OneNote上,我更放心把我的数据放到微软那里而不是番茄钟那里,而且我认为衡量番茄工作法是否执行得好的标准是我的工作,而不是图表里展示给我的番茄数量,所以我对图表、统计、任务列表这些功能不是太感兴趣。

说了这么多其实还是因为我懒,平时上班已经处理这么多数据了,图表我也玩腻了,自己玩玩的东西就不想做这些工作,而且存储数据是要负责任的,我可不想负责任。

3. 创建项目

首先安装Windows Template Studio,它可以帮助开发者简单地创建UWP项目。

安装后在创建新项目界面选择Windows Template Studio(Universal Windows),然后在打开的精灵控件窗口一步步创建一个已经包含基础功能的UWP应用。

项目名称是OnePomodoro,项目类型选择Blank,Design pattern选择了Prism,因为在WPF中用惯了Prsim。不过我不懂UWP中Prism怎么用,所以我也没打算马上就用,只是个小项目轻轻松松地CodeBehind一把梭。

页面项选择了Settings页面。功能项添加了好像很有趣的Toast Notifications、Live Tile等一系列的通知功能。

稍等几分钟后,一个包含了基本功能的UWP项目就创建好了,项目中还贴心地提示了很多需要处理的Todo项,运行效果如下:

然后添加Microsoft.Toolkit.Uwp.UIMicrosoft.Toolkit.Uwp.UI.Animations引用,这两个包是Windows Community Toolkit的一部分,提供了很多有用的Converter和动画。

第一次运行应用时会弹出一些示例通知,现在还不需要做到这么全面,找到App.xaml.cs里的LaunchApplicationAsync把里面一些通知相关的代码注释掉,然后就可以开始实现我们的功能了。

protected override async Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
{
    await LaunchApplicationAsync(PageTokens.MainPage, null);
}

private async Task LaunchApplicationAsync(string page, object launchParam)
{
    await ThemeSelectorService.SetRequestedThemeAsync();
    NavigationService.Navigate(page, launchParam);
    SetupTitlebar();
    Window.Current.Activate();
    //await Container.Resolve<IWhatsNewDisplayService>().ShowIfAppropriateAsync();
    //await Container.Resolve<IFirstRunDisplayService>().ShowIfAppropriateAsync();
    //Container.Resolve<ILiveTileService>().SampleUpdate();
    //Container.Resolve<IToastNotificationsService>().ShowToastNotificationSample();
}

4. 具体实现

最终效果就是这样,一个单页面的应用,点击开始启动工作的计时器,点击停止(或者倒计时结束)转到休息的计时器,如此往返几次,一天的工资就到手了。

很多计时器是个由分针和秒针组成的表盘,但我已经玩腻了这种做法,简单些反而有更多的快乐。

为了好看首先要移除应用的标题栏,将CoreApplicationViewTitleBar.ExtendViewIntoTitleBar属性设置为True:

private void ExtendAcrylicIntoTitleBar()
{
    CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
    ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
    titleBar.ButtonBackgroundColor = Colors.Transparent;
    titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
}

因为背景是黑色,需要将主题也改为黑色主题,在App.xaml中修改RequestedTheme为Dark:

RequestedTheme="Dark"

然后实现MainViewModel。使用到DispatcherTimer进行计时,用DelegateCommand实现命令,这些都只用到WPF的知识:

public class MainViewModel: ViewModelBase
{
    public bool IsInPomodoro { get; }
    public bool IsTimerInProgress { get; }
    public TimeSpan RemainingBreakTime { get; }
    public TimeSpan RemainingPomodoroTime { get; }
    public DelegateCommand StartTimerCommand { get; }
    public DelegateCommand StopTimerCommand { get; }
}

整个UI上就只有4行字,以及停止和开始两个按钮。(上面效果图里还有一个按钮,那是第二版做的)。整个番茄钟由IsInPomodoro和IsTimerInProgress组合成准备开始工作,正在工作,准备休息,正在休息四种状态,MainView上的元素就由IsInPomodoro和IsTimerInProgress这两个属性控制是否显示。

为了用这两个Bool属性控制UI元素的显示和隐藏需要用到Converter,Microsoft.Toolkit.Uwp.UI提供了BoolToVisibilityConverter,我需要再实现一个反过来的NegationBoolToVisibilityConverter:

public class NegationBoolToVisibilityConverter : BoolToObjectConverter
{
    public NegationBoolToVisibilityConverter()
    {
        base.TrueValue = Visibility.Collapsed;
        base.FalseValue = Visibility.Visible;
    }
}

这两个Converter配合IsInPomodoro和IsTimerInProgress两个属性用于控制是否显示。然后再使用BoolToObjectConverter定义两个Converter用于控制文字的水平和垂直对齐:

converters:BoolToObjectConverter TrueValue="Top"
                                 FalseValue="Bottom"
                                 x:Key="BoolToVerticalAlignmentConverter" />
converters:BoolToObjectConverter TrueValue="Left"
                                 FalseValue="Right"
                                 x:Key="BoolToVerticalHorizontalAlignment" />

整个布局大概这样

<StackPanel VerticalAlignment="{Binding IsInPomodoro,Converter={StaticResource BoolToVerticalAlignmentConverter}}"
            HorizontalAlignment="{Binding IsInPomodoro,Converter={StaticResource BoolToVerticalHorizontalAlignment}}">
    <TextBlock Text="In Work"
               Visibility="{Binding IsInPomodoro,Converter={StaticResource BoolToVisibilityConverter}}"/>

    <TextBlock Text="{Binding RemainingPomodoroTime,Converter={StaticResource FormatStringConverter},ConverterParameter=mm\\:ss}"
               Visibility="{Binding IsInPomodoro,Converter={StaticResource BoolToVisibilityConverter}}"/>

    <TextBlock Text="{Binding RemainingBreakTime,Converter={StaticResource FormatStringConverter},ConverterParameter=mm\\:ss}"
               Visibility="{Binding IsInPomodoro,Converter={StaticResource NegationBoolToVisibilityConverter}}"/>

    <TextBlock Text="Take a Break"
               Visibility="{Binding IsInPomodoro,Converter={StaticResource NegationBoolToVisibilityConverter}}"/>
</StackPanel>

<StackPanel HorizontalAlignment="Left"
            VerticalAlignment="Bottom"
            Orientation="Horizontal">
    <Button Content=""
            Visibility="{Binding IsTimerInProgress,Converter={StaticResource NegationBoolToVisibilityConverter}}"
            Command="{Binding StartTimerCommand}" />
    <Button Content=""
            Visibility="{Binding IsTimerInProgress,Converter={StaticResource BoolToVisibilityConverter}}"
            Command="{Binding StopTimerCommand}" />
</StackPanel>

到这时候,MainView和MainViewModel几乎只用到WPF的知识,虽然听说DispatcherTimer比较伤性能,也没有用x:Binding代替Binding,主要是想到项目刚开始就尽量用WPF的知识实现所有功能,以后再试用UWP的API。不过动画我倒是没用Storyboard,而是用Composition API做动画。

composition-animation有很多种,我选择使用Windows Community Toolkit中的Implicit Animations,因为它很适合入门。

Implicit Animations(又称为隐式动画)是一种用于描述当属性(例如Opacity or Offset)改变时如何使用动画响应的Composition Animations。而ShowAnimations和HideAnimations分别用于定义当元素显示/隐藏或从VisualTree上添加/移除时的动画效果。

MainView里当状态改变只会引起元素显示/隐藏或者对齐的改变,所以很适合使用隐式动画。例如这段番茄钟倒计时的动画,即显示时从下面200像素向上移动,并且淡入,耗时1.5秒;隐藏时用0.5秒淡出。

<animations:Implicit.ShowAnimations>
    <animations:ScalarAnimation Target="Translation.Y"
                                Duration="0:0:1.5"
                                From="200"
                                To="0" />
    <animations:OpacityAnimation Duration="0:0:1.5"
                                 From="0"
                                 To="1" />
</animations:Implicit.ShowAnimations>

<animations:Implicit.HideAnimations>
    <animations:OpacityAnimation Duration="0:0:0.5"
                                 From="1"
                                 To="0" />
</animations:Implicit.HideAnimations>

最终动画效果如下:

5. 发布

就这样一个基本的番茄钟就做好了,之后就是打包和发布。随便画个渐变的背景,再画个圈,Logo就做好了。然后在Package.appxmanifest里处理一下信息,就打包了,就发布了。

官方文档有很详尽的发布指南,微软合作伙伴中心的图形界面也简单易用,稍微折腾一下就可以发布,过几天就可以在Store里见到自己的应用。

每次自己打包都很麻烦,可以将Github仓库(假设有的话)和AppCenter关联起来,每次提交到Github都由AppCenter打安装包。AppCenter打包后即可把安装包下载回来,再发布(话说没有直接帮我发布的方法吗?)

林德熙的这篇文章详细介绍了如何操作。

还可以获得一个徽标,显示编译结果。

6. 结语

Edi.Wang被UWP伤害后抛弃了UWP还像个怨念少女那样每天对别人说其实是要说服自己“我才没有喜欢UWP我最讨厌UWP讨厌讨厌最讨厌了”但这样每天每天每天都说UWP是个坏家伙是个坏家伙搞到我反而很想试一试这个坏家伙现在终于忍不了了晚上把switch扔在床上把自己关在书房里亲自动手调教UWP。

总的来说这是个愉快的编程体验:用惯的WPF知识和官方文档,即可实现一个自己用的应用并发布——除了商店偶尔抽风导致自己都下载不了自己的应用外。

顺便一提OnePomodoro的中文名称是一个番茄钟(谢绝对命名品味的一切批评),已经可以在Store下载

最后提一下左下角的按钮。因为1809的Button有了圆角的API,圆形的Reveal按钮很容易实现,只需要BasedOn ButtonRevealStyle再把CornerRadius有那么大就搞那么大:

<Style TargetType="Button" x:Key="EllipseButtonRevealStyle" BasedOn="{StaticResource ButtonRevealStyle}">
    <Setter Property="CornerRadius" Value="100"/>
    <Setter Property="Background" Value="Transparent"/>
</Style>

这样省去了很多修改ControlTemplate的麻烦,所以项目的最低版本即是1809,反正只是玩玩的东西不要顾虑太多。

7. 如何安装

可以打开这个链接安装 一个番茄钟,也可以在Microsoft Store中搜索“OnePomodoro”或“一个番茄钟”进行安装。

如果不能安装?我相信,等缘分到了自然可以安装。

8. 参考

通过《番茄工作法图解》复习番茄工作法

Windows Template Studio quickly builds a UWP app, using a wizard-based UI to turn your needs into a foundation of Windows 10 patterns and best practices

Overview - Visual Studio App Center Microsoft Docs

合成动画 - Windows UWP applications Microsoft Docs

Implicit Animations XAML Attached Properties - Windows Community Toolkit Microsoft Docs

9. 源码

OnePomodoro

原文地址:https://blog.51cto.com/14648815/2460609

时间: 2024-10-02 11:34:52

[UWP]从头开始创建并发布一个番茄钟的相关文章

[UWP]为番茄钟应用设计一个平平无奇的状态按钮

1. 为什么需要设计一个状态按钮 OnePomodoro应用里有个按钮用来控制计时器的启动/停止,本来这应该是一个包含"已启动"和"已停止"两种状态的按钮,但我以前在WPF和UWP上做过太多StateButton.ProgressButton之类的东西,已经厌倦了这种控件,所以我在OnePomodoro应用里只是简单地使用两个按钮来实现这个功能: <Button Content="" Visibility="{x:Bind Vi

webservice之简单创建和发布(一个加法运算)

webservice之简单创建和发布(一个加法运算) 开发工具 visual studio 2010 WebService:严格来说是行业标准,不是技术,使用XML扩展标记语言来表示数据(这个是夸语言和平台的关键).微软的Web服务实现称为ASP.NET Web Service.它使用Soap简单对象访问协议来实现分布式环境里应用程序之间的数据交互. WSDL来实现服务接口相关的描述.此外Web services 可以注册到UDDI中心.供其客户查找使用.后来微软做了ASP.NET Web Se

Skype For Business 2015实战系列11:创建并发布拓扑

Skype For Business 2015实战系列11:创建并发布拓扑 Skype For Business Server安装前需要先定义好拓扑,因为我们要在拓扑中的每台服务器上安装 Skype for Business Server 系统,必须首先创建和发布一个拓扑.发布拓扑时,拓扑信息会载入中央管理存储数据库.如果这是 Enterprise Edition 池,您将在初次发布新拓扑时创建中央管理存储数据库.如果是 Standard Edition,则需要运行部署向导中的"准备第一个 St

番茄钟App(Pomodoro Tracker)

最近为了学习Swift编程语言,写了一个番茄钟的App(Pomodoro Tracker).刚上线的1.2版本增加了Apple Watch的支持. iPhone版 Apple Watch版 如果你跟我一样有拖延症的话,不妨试用一下或许会解决你的时间管理问题. 另外欢迎提建议和反馈,谢谢. 其它博文: Swift learning resources Xcode 6 模拟器路径 Scrum Planning Card Watch?Kit Learning Resources More blog p

Datazen图表创建和发布

 Datazen是被微软收购的移动端全平台的数据展现解决方案.此篇主要介绍如何创建和发布图表. 如前面介绍,Datazen图表的创建和发布是通过Publisher的应用,它是Windows 8应用商店下的一个免费应用.也就是说,想要创建和发布图表,你需要有一台Win8的电脑,或者一个Surface. 点击Win8开始屏幕,点击应用商店搜索Datazen. 有两个搜索结果是Datazen的,忽视并且鄙视另外那个.下面那个Publisher就是此篇提到的创建和发布图表用的应用,第一个结果是查看图

如何发布一个自定义Node.js模块到NPM(详细步骤)

咱们闲话不多说,直接开始! 由于我从没有使用过MAC,所以我不保证本文中介绍的操作与MAC一致. 文章开始我先假定各位已经在window全局安装了Node.js,下面开始进行详细步骤介绍: 本文本着,以极少的文字说明以及极少的代码书写为原则来给大家演示! 文章中上传的模块不具备任何意义! 一.封装node.js模块时的必须项 1.创建package.json 每一个完整封装的node模块,必须含有一个参数明确的package.json文件! 以下为package.json的最精简配置: { "n

NET Core MVC 在linux上的创建及发布

NET Core MVC 在linux上的创建及发布 前言 ASP.NET core转眼都发布半月多了,社区最近也是非常活跃,虽然最近从事python工作,但也一直对.NET念念不忘,看过了园区大神们搭建的Asp.net core项目之后,自己也是跃跃欲试,准备搞一下ASP.NET Core mvc的创建和部署,于是便有了这篇文章,希望能够帮助到你. 环境准备 这是我的开发环境,使用的nginx是nginx 1.6.3 直接yum install,然后需要安装dotnet环境,可以参照官网教程h

npm创建和发布模块

今天项目需要使用npm去创建一个模块,然后我查询了了npm的使用文档(Working with private modules),然后对其进行了整理. 一.在操作之前,我们首先要将npm装好,并且登录(没有npm账号的需要先去注册一个帐号). 命令: $sudo npm install -g npm $npm login (npm logout 是退出,如果你不确定是否已经登录,你可以先试用此命令退出,然后重新登录) 二.创建一个文件夹 命令: $mkdir npmexample $cd npm

Gradle入门:创建二进制发布版本

在创建了一个实用的应用程序之后,我们可能想将其与他人分享.其中一种方式就是创建一个可以从网站上下载的二进制文件. 这篇教程描述了如何创建一个二进制发布版本,满足以下需求: 二进制发布一定不能使用所谓的“fat jar”方式.换句话说,我们应用程序中的所有依赖一定不能被打包到该程序相同的jar包中. 二进制发布必须包含针对*nix和Windows操作系统的启动副本. 二进制发布的根目录必须包含许可证. 我们开始吧. 创建二进制发布文件 Application插件是一种Gradle插件,让我们可以运