1. 程式人生 > >Photoshop和WPF雙劍配合,打造炫酷個性的進度條控件

Photoshop和WPF雙劍配合,打造炫酷個性的進度條控件

span nan ui設計 10.6 demo 一個 tar gis 變更

原文:Photoshop和WPF雙劍配合,打造炫酷個性的進度條控件

現在如果想打造一款專業的App,UI的設計和操作的簡便性相當重要。UI設計可以借助Photoshop或者AI等設計工具,之前了解到WPF設計工具Expression Blend可以直接導入PSD文件或者AI設計文件(當然不是全部特征支持),最近研究了一下,也費了一番周折,好在最後實現了預期的效果。下面將step by step用示例說明如何先用PS構建一個矢量圖形模板,然後用Expression Blend導入PSD文件,並獲取PATH的Data值,為打造一款炫酷的個性進度條控件構建美觀UI。

1、打開Photoshop,新建一個空白圖層,點選PS的圖案圖章工具:

技術分享圖片

2、選擇畫筆,選用喜歡的筆刷(可以到網站上下載免費的筆刷),如下圖:

技術分享圖片

在合適位置點擊後,如下圖所示。

技術分享圖片

3、按住CTRL,選中圖層,切換到路徑面板,點擊 【從選取創建工作路徑】 按鈕,如下圖:

技術分享圖片

技術分享圖片

註意上圖的紅框按鈕,就是【從選取創建工作路徑】,點擊後出現下圖:

技術分享圖片

4、這是最關鍵的一步,創建矢量蒙板,切換到圖層面板,點選【鋼筆】工具,在圖形上右鍵菜單中選擇【創建矢量蒙板】項,如下圖所示:

技術分享圖片

然後PS中可以看到下圖的效果,說明創建成功。

技術分享圖片

保存PS文件為進度條.PSD文件待用。

5、打開Expression Blend 4新建一個WPF項目,然後導入PSD文件,如下圖:

技術分享圖片

技術分享圖片

導入成功後,可以復制該圖形的clip數據,這就是WPF中PATH所需要的Data值。

技術分享圖片

下面來創建一個炫酷的WPF進度條控件。

6、在VS2010中重新打開該項目,並添加一個WPF自定義控件庫,如下圖:

技術分享圖片

17 編寫控件UI和後臺代碼,如下所示:

 1 <ResourceDictionary
 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4     xmlns:local
="clr-namespace:WpfCustomProgressControl"> 5 6 <Style TargetType="{x:Type local:CustomProgressControl}"> 7 <Setter Property="Template"> 8 <Setter.Value> 9 <ControlTemplate TargetType="{x:Type local:CustomProgressControl}"> 10 <Grid x:Name="PART_container" 11 Background="{TemplateBinding Background}" 12 Width="{TemplateBinding Width}" 13 Height="{TemplateBinding Height}"> 14 <Path x:Name="PART_foreground_P" 15 Visibility="Collapsed" 16 Stretch="Fill" 17 Stroke="Transparent" 18 Fill="{TemplateBinding Foreground}" 19 StrokeThickness="2" 20 Data="F1M56,33C58,33 60,33 62,33 61.667,33.667 61.333,34.333 61,35 57.794,34.859 53.856,36.079 56,33z M49,24C54.364,24.735 53.554,24.821 56,28 53.807,30.696 55.287,29.902 51,31 50,30 49,29 48,28 48.333,26.667 48.667,25.333 49,24z M62,22C63.666,22.333 65.333,22.667 67,23 66.333,27.571 65.935,27.376 64,30 63,29.333 62,28.667 61,28 61,27.667 61,27.333 61,27 61.333,25.333 61.667,23.666 62,22z M46,15C46.667,15 47.333,15 48,15 47.333,17.333 46.667,19.667 46,22 45.333,22 44.667,22 44,22 44.667,19.667 45.333,17.333 46,15z M63,13C64.923,14.392 63.599,13.101 65,15 64.333,14.333 63.667,13.667 63,13z M55,12C56.666,12.667 58.333,13.333 60,14 60,15.333 60,16.667 60,18 59.333,18 58.667,18 58,18 54.722,21.928 52.838,16.561 52,14 53,13.333 54,12.667 55,12z M128,1C128.667,1 129.333,1 130,1 128.882,10.058 122.793,12.326 122,23 126.364,22.028 126.876,21.206 131,22 130,23.333 129,24.667 128,26 110.659,32.752 112.704,45.252 103,59 95.769,69.245 82.761,82.131 72,89 72.621,101.092 82.373,112.463 90,118 90.333,118 90.667,118 91,118 93.274,107.421 107.464,106.386 104,92 101.667,87.667 99.333,83.333 97,79 98,78 99,77 100,76 122.812,77.152 112.786,100.488 115,114 116.666,115.666 118.333,117.333 120,119 127.359,142.373 118.776,160.626 106,168 110.337,176.877 114.918,188.188 121,197 127.441,206.332 140.794,210.508 148,220 146.506,223.067 146.885,223.215 144,225 113.08,236.802 62.376,138.34 36,147 34.077,151.751 32.347,152.761 28,155 17.556,150.255 9.333,141.565 9,127 13.999,120.001 19,112.999 24,106 22.667,102.667 21.333,99.333 20,96 7.555,96.019 4.392,90.889 1,82 1.465,74.486 3.768,68.82 9,66 19.848,56.341 31.922,71.946 38,77 37.406,83.299 36.792,87.413 39,92 41.333,89.667 43.667,87.333 46,85 81.009,67.269 105.228,31.536 128,1z" /> 21 22 <Rectangle x:Name="PART_mask" 23 Fill="{TemplateBinding Background}" 24 VerticalAlignment="Stretch" 25 HorizontalAlignment="Stretch" /> 26 27 <Path x:Name="PART_outline_P" 28 Visibility="Collapsed" 29 Stretch="Fill" 30 Stroke="{TemplateBinding BorderBrush}" 31 Fill="Transparent" 32 StrokeThickness="2" 33 Data="F1M56,33C58,33 60,33 62,33 61.667,33.667 61.333,34.333 61,35 57.794,34.859 53.856,36.079 56,33z M49,24C54.364,24.735 53.554,24.821 56,28 53.807,30.696 55.287,29.902 51,31 50,30 49,29 48,28 48.333,26.667 48.667,25.333 49,24z M62,22C63.666,22.333 65.333,22.667 67,23 66.333,27.571 65.935,27.376 64,30 63,29.333 62,28.667 61,28 61,27.667 61,27.333 61,27 61.333,25.333 61.667,23.666 62,22z M46,15C46.667,15 47.333,15 48,15 47.333,17.333 46.667,19.667 46,22 45.333,22 44.667,22 44,22 44.667,19.667 45.333,17.333 46,15z M63,13C64.923,14.392 63.599,13.101 65,15 64.333,14.333 63.667,13.667 63,13z M55,12C56.666,12.667 58.333,13.333 60,14 60,15.333 60,16.667 60,18 59.333,18 58.667,18 58,18 54.722,21.928 52.838,16.561 52,14 53,13.333 54,12.667 55,12z M128,1C128.667,1 129.333,1 130,1 128.882,10.058 122.793,12.326 122,23 126.364,22.028 126.876,21.206 131,22 130,23.333 129,24.667 128,26 110.659,32.752 112.704,45.252 103,59 95.769,69.245 82.761,82.131 72,89 72.621,101.092 82.373,112.463 90,118 90.333,118 90.667,118 91,118 93.274,107.421 107.464,106.386 104,92 101.667,87.667 99.333,83.333 97,79 98,78 99,77 100,76 122.812,77.152 112.786,100.488 115,114 116.666,115.666 118.333,117.333 120,119 127.359,142.373 118.776,160.626 106,168 110.337,176.877 114.918,188.188 121,197 127.441,206.332 140.794,210.508 148,220 146.506,223.067 146.885,223.215 144,225 113.08,236.802 62.376,138.34 36,147 34.077,151.751 32.347,152.761 28,155 17.556,150.255 9.333,141.565 9,127 13.999,120.001 19,112.999 24,106 22.667,102.667 21.333,99.333 20,96 7.555,96.019 4.392,90.889 1,82 1.465,74.486 3.768,68.82 9,66 19.848,56.341 31.922,71.946 38,77 37.406,83.299 36.792,87.413 39,92 41.333,89.667 43.667,87.333 46,85 81.009,67.269 105.228,31.536 128,1z" /> 34 35 <TextBlock x:Name="PART_percentage_text" 36 VerticalAlignment="Center" 37 HorizontalAlignment="Center" 38 FontSize="16" 39 FontWeight="ExtraBlack" 40 Foreground="{TemplateBinding TextForeground}"/> 41 42 </Grid> 43 </ControlTemplate> 44 </Setter.Value> 45 </Setter> 46 </Style> 47 48 </ResourceDictionary>
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Windows;
  6 using System.Windows.Controls;
  7 using System.Windows.Data;
  8 using System.Windows.Documents;
  9 using System.Windows.Input;
 10 using System.Windows.Media;
 11 using System.Windows.Media.Imaging;
 12 using System.Windows.Navigation;
 13 using System.Windows.Shapes;
 14 
 15 namespace WpfCustomProgressControl
 16 {
 17 
 18     [TemplatePart(Name = "PART_mask", Type = typeof(Rectangle))]
 19     [TemplatePart(Name = "PART_container", Type = typeof(Grid))]
 20     [TemplatePart(Name = "PART_percentage_text", Type = typeof(TextBlock))]
 21     [TemplatePart(Name = "PART_foreground_P", Type = typeof(Path))]
 22     [TemplatePart(Name = "PART_outline_P", Type = typeof(Path))]
 23 
 24     public class CustomProgressControl : ProgressBar
 25     {
 26         static CustomProgressControl()
 27         {
 28             DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomProgressControl), new FrameworkPropertyMetadata(typeof(CustomProgressControl)));
 29 
 30         }
 31 
 32         Rectangle mask;
 33         Grid container;
 34         TextBlock percentageText;
 35         Path foreground_P;
 36         Path outline_P;
 37 
 38         #region TextForeground 文本
 39         public SolidColorBrush TextForeground
 40         {
 41             get { return (SolidColorBrush)GetValue(TextForegroundProperty); }
 42             set { SetValue(TextForegroundProperty, value); }
 43         }
 44 
 45         public static readonly DependencyProperty TextForegroundProperty =
 46             DependencyProperty.Register("TextForeground", typeof(SolidColorBrush),
 47                                 typeof(CustomProgressControl),
 48                                 new FrameworkPropertyMetadata(new SolidColorBrush(Colors.DarkGray)));
 49         #endregion
 50 
 51         public override void OnApplyTemplate()
 52         {
 53             base.OnApplyTemplate();
 54 
 55 
 56             foreground_P = this.Template.FindName("PART_foreground_P", this) as Path;
 57             outline_P = this.Template.FindName("PART_outline_P", this) as Path;
 58             mask = this.Template.FindName("PART_mask", this) as Rectangle;
 59             container = this.Template.FindName("PART_container", this) as Grid;
 60             percentageText = this.Template.FindName("PART_percentage_text", this) as TextBlock;
 61             if (foreground_P != null)
 62             {
 63                 foreground_P.Visibility = Visibility.Visible;
 64                 outline_P.Visibility = Visibility.Visible;
 65             }
 66             Width = double.IsNaN(Width) ? 50 : Width;
 67             Height = double.IsNaN(Height) ? 135 : Height;
 68 
 69             Minimum = double.IsNaN(Minimum) ? 0 : Minimum;
 70             Maximum = double.IsNaN(Maximum) ? 100 : Maximum;
 71 
 72             if (mask != null)
 73             {
 74                 var percentageValue = Value / Maximum;
 75                 var awayMargin = percentageValue * Height;
 76                 var percentageString = string.Empty;
 77 
 78                 if (percentageValue > 0)
 79                     percentageString = (percentageValue * 100).ToString("##");
 80                 else if (percentageValue == 0)
 81                     percentageString = "0";
 82 
 83                 percentageText.Text = string.Format("{0}%", string.IsNullOrEmpty(percentageString) ? "0" : percentageString);
 84 
 85                 mask.Margin = new Thickness(0, 0, 0, awayMargin);
 86             }
 87 
 88             container.Clip = new RectangleGeometry
 89             {
 90                 Rect = new Rect(0, 0, Width, Height)
 91             };
 92 
 93             mask.Width = Width;
 94             mask.Height = Height;
 95         }
 96 
 97         protected override void OnValueChanged(double oldValue, double newValue)
 98         {
 99             base.OnValueChanged(oldValue, newValue);
100 
101             if (Value < Minimum)
102             {
103                 Value = Minimum;
104             }
105 
106             if (Value > Maximum)
107             {
108                 Value = Maximum;
109             }
110 
111             if (mask != null)
112             {
113                 var percentageValue = Value / Maximum;
114                 var awayMargin = percentageValue * Height;
115                 var percentageString = string.Empty;
116 
117                 if (percentageValue > 0)
118                     percentageString = (percentageValue * 100).ToString("##");
119                 else if (percentageValue == 0)
120                     percentageString = "0";
121 
122                 percentageText.Text = string.Format("{0}%", string.IsNullOrEmpty(percentageString) ? "0" : percentageString);
123                 //蒙板來變更進度
124                 mask.Margin = new Thickness(0, 0, 0, awayMargin);
125 
126             }
127         }
128     }
129 }

18 在WpfPSDemo的主界面上拖入控件,並定制屬性,代碼如下:

 1 <Window
 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4     xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
 5     x:Class="WpfPSDemo.MainWindow"
 6     x:Name="Window"  BorderThickness="0"
 7     Title="MainWindow"
 8     Width="430" Height="480" xmlns:my="clr-namespace:WpfCustomProgressControl;assembly=WpfCustomProgressControl">
 9     <my:CustomProgressControl  Name="customProgressControl1" Width="200" Height="200" Value="50" Background="Yellow" Foreground="Red" BorderBrush="red" />
10 </Window>
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Windows;
 5 using System.Windows.Controls;
 6 using System.Windows.Data;
 7 using System.Windows.Documents;
 8 using System.Windows.Input;
 9 using System.Windows.Media;
10 using System.Windows.Media.Imaging;
11 using System.Windows.Shapes;
12 using System.Threading;
13 namespace WpfPSDemo
14 {
15     /// <summary>
16     /// MainWindow.xaml 的交互邏輯
17     /// </summary>
18     public partial class MainWindow : Window
19     {
20         Thread timeThread;
21         int i = 0;
22         public MainWindow()
23         {
24             this.InitializeComponent();
25             this.customProgressControl1.Value = 0;
26             this.Background = Brushes.Yellow;
27             timeThread = new Thread(new ThreadStart(DispatcherThread));
28             timeThread.Start();
29 
30         }
31         public void DispatcherThread()
32         {
33             //可以通過循環條件來控制UI的更新
34             while (true)
35             {
36                 ///線程方法委托(無參方法)
37                 this.customProgressControl1.Dispatcher.BeginInvoke(new Action(UpdateTime));
38                 Thread.Sleep(200);
39             }
40         }
41 
42         private void UpdateTime()
43         {
44 
45             if (i < 100)
46             {
47                 i++;
48                 this.customProgressControl1.Value = i;
49             }
50             else
51             {
52                 timeThread.Abort();
53             }
54 
55         }
56     }
57 }

運行代碼,效果如下:
技術分享圖片

Photoshop和WPF雙劍配合,打造炫酷個性的進度條控件