在PC上我一直使用「小番茄」做爲個人番茄鍾軟件,我把它打開後放在副顯示器最大化,這樣不只可讓它盡到本分,並且還能夠告訴個人同事「我正在專心工做」。但是我老是嫌棄它的手感不夠愉悅,總想本身寫一個番茄鍾軟件,正好最近好久沒寫UWP應用了很手癢,因而就抽空寫了個自用的番茄鍾併發布到微軟應用商店。html
結果手感也並不愉悅。git
另外,原本原本我也打算用Storyboard實現動畫,但火火老是勸我不要搞Storyboard,要用Composition API作動畫。Storyboard的能力是有極限的,我從短暫的UWP生涯當中學到一件事,人越是玩弄動畫,動畫就越可能由於沒有料到的事態而失敗……除非超越Storyboard。因此我也不作Sotryboard啦。程序員
微軟的應用商店是一個還不錯的平臺,WPF程序員能夠基於現有的知識輕易地建立一個UWP應用併發布到應用商店。尤爲是如今微軟的審覈比較寬鬆,只要是對得起本身良心的應用通常都能經過審覈。雖然由於商店抽風我本身都很難下載到本身的應用。這篇文章將講解從建立UWP項目到發佈到商店的整個流程。github
我只想要一個能夠倒計時的Timer,順便玩玩UWP的新API,因此原則上越簡單越好,而後想到什麼作什麼。編程
不少番茄鍾軟件都會提供任務列表功能,還能夠經過圖表展現番茄數量、完成任務數量的統計。不過我已經有To-Do和Azure Devops,平時的工做還會記錄在OneNote上,我更放心把個人數據放到微軟那裏而不是番茄鍾那裏,並且我認爲衡量番茄工做法是否執行得好的標準是個人工做,而不是圖表裏展現給個人番茄數量,因此我對圖表、統計、任務列表這些功能不是太感興趣。windows
說了這麼多其實仍是由於我懶,平時上班已經處理這麼多數據了,圖表我也玩膩了,本身玩玩的東西就不想作這些工做,並且存儲數據是要負責任的,我可不想負責任。api
首先安裝Windows Template Studio,它能夠幫助開發者簡單地建立UWP項目。併發
安裝後在建立新項目界面選擇Windows Template Studio(Universal Windows)
,而後在打開的精靈控件窗口一步步建立一個已經包含基礎功能的UWP應用。app
項目名稱是OnePomodoro
,項目類型選擇Blank
,Design pattern選擇了Prism,由於在WPF中用慣了Prsim。不過我不懂UWP中Prism怎麼用,因此我也沒打算立刻就用,只是個小項目輕輕鬆鬆地CodeBehind一把梭。async
頁面項選擇了Settings頁面。功能項添加了好像頗有趣的Toast Notifications、Live Tile等一系列的通知功能。
稍等幾分鐘後,一個包含了基本功能的UWP項目就建立好了,項目中還貼心地提示了不少須要處理的Todo項,運行效果以下:
而後添加Microsoft.Toolkit.Uwp.UI和Microsoft.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();
}
最終效果就是這樣,一個單頁面的應用,點擊開始啓動工做的計時器,點擊中止(或者倒計時結束)轉到休息的計時器,如此往返幾回,一天的工資就到手了。
不少計時器是個由分針和秒針組成的錶盤,但我已經玩膩了這種作法,簡單些反而有更多的快樂。
爲了好看首先要移除應用的標題欄,將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>
最終動畫效果以下:
就這樣一個基本的番茄鍾就作好了,以後就是打包和發佈。隨便畫個漸變的背景,再畫個圈,Logo就作好了。而後在Package.appxmanifest裏處理一下信息,就打包了,就發佈了。
官方文檔有很詳盡的發佈指南,微軟合做夥伴中心的圖形界面也簡單易用,稍微折騰一下就能夠發佈,過幾天就能夠在Store裏見到本身的應用。
每次本身打包都很麻煩,能夠將Github倉庫(假設有的話)和AppCenter關聯起來,每次提交到Github都由AppCenter打安裝包。AppCenter打包後便可把安裝包下載回來,再發布(話說沒有直接幫我發佈的方法嗎?)
林德熙的這篇文章詳細介紹瞭如何操做。
還能夠得到一個徽標,顯示編譯結果。
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,反正只是玩玩的東西不要顧慮太多。
能夠打開這個連接安裝 一個番茄鍾,也能夠在Microsoft Store中搜索「OnePomodoro」或「一個番茄鍾」進行安裝。
若是不能安裝?我相信,等緣分到了天然能夠安裝。
Overview - Visual Studio App Center Microsoft Docs
合成動畫 - Windows UWP applications Microsoft Docs
Implicit Animations XAML Attached Properties - Windows Community Toolkit Microsoft Docs