MetroGridHelper:WP7設(shè)計師與開發(fā)人員的得力助手
譯文作者簡介:Jeff Wilcox,微軟高級軟件開發(fā)工程師,不久前,調(diào)往微軟Windows Azure組,負(fù)責(zé)微軟云技術(shù)的開源項目。Jeff Wilcox曾負(fù)責(zé)開發(fā)了Windows Phone平臺的Foursqaure客戶端,并參與了無數(shù)Silverlight工具包、Windows Phone 7.0、7.1開發(fā)包,Windows Phone用戶界面控制、幫助,以及許多其他重要項目。
【51CTO譯文】作為沉浸于開發(fā)行業(yè)多年的老手,大家一定對這些話題并不陌生:整理頁面邊距、對齊圖像內(nèi)容以及讓自己的應(yīng)用程序更美觀。隨著軟件消費者中“外貌協(xié)會”成員的比重不斷上升,用戶界面不夠搶眼的應(yīng)用幾乎已經(jīng)無法在市場上占得一席之地。
不久前,我有幸參加了Windows Phone設(shè)計團(tuán)隊舉辦的“美觀開發(fā)空間”活動。我要由衷地贊嘆,這是一次真正的創(chuàng)意空間交流活動,到處是有趣的參與者、舒緩的音樂以及為市場創(chuàng)造出更好、更漂亮的應(yīng)用程序的熱烈渴求。
在活動中我一直坐在兩位用戶體驗設(shè)計師Corrina與Arturo身邊,與他們討論設(shè)計工作中的原則性取向;很偶然地,我們的話題轉(zhuǎn)移到一副簡潔而相當(dāng)美觀的網(wǎng)格圖上,這也正是二位在Windows Phone平臺上開發(fā)的主要焦點。圖像由多個紅色正方形構(gòu)成,每個方形為25x25像素,兩個方形之間相隔12像素,也就是說每個獨立單元都擁有寬高為24像素的反襯背景。(還是那句話,Metro風(fēng)格要求邊框長度始終為12的整數(shù))
設(shè)計將使用典型的Photoshop層來容納這些方形,或者是在應(yīng)用程序頁面之上插入XAML借以完成圖形對齊、網(wǎng)格設(shè)計及位置調(diào)整等等。
我的想法是:如果最終外觀設(shè)計方案能夠與Windows Phone上現(xiàn)有的性能計數(shù)器相似,那么肯定會大受歡迎——在調(diào)試時,我們能夠?qū)⑦@套網(wǎng)格重疊覆蓋在整個應(yīng)用程序框架上,使其成為獨立而完整的全局顯示方案。就在活動過程當(dāng)中,我即興用代碼將自己的想法表達(dá)了出來,下面請大家分享我的成果。
要使用這款計數(shù)器,我們只需打開App.xaml.cs文件(這里囊括了其它多款性能計數(shù)器),并將其添加進(jìn)來。如果大家只是打算簡單設(shè)計一下,那么我建議各位直接將其啟用,這樣一來我們就能夠讓它作用于實機及模擬器中的應(yīng)用程序。之所以要把它與模擬器關(guān)聯(lián)起來,是因為我們能夠?qū)⒆罱K顯示效果通過截圖與朋友及家人分享,并聆聽他們在圖像位置方面提出的意見。
- // Show graphics profiling information while debugging.
 - if (System.Diagnostics.Debugger.IsAttached)
 - {
 - // Display the current frame rate counters.
 - Application.Current.Host.Settings.EnableFrameRateCounter = true;
 - // Display the metro grid helper.
 - MetroGridHelper.IsVisible = true;
 
以下是這段簡單的代碼在與小型應(yīng)用程序協(xié)作時顯示出的效果:
在這個例子中,我遇到了Windows Phone設(shè)計中的經(jīng)典“bug”:文本信息區(qū)塊之一在插入過程中未能正確顯示應(yīng)有的Metro風(fēng)格。也就是說,該區(qū)塊的左側(cè)邊距為“0”,而不是Metro要求的12像素,這使得對應(yīng)文字內(nèi)容比其它字體更靠左。通過上圖中正方形的對比,相信大家能更清晰地理解我遇到的問題,字體錯位現(xiàn)象十分明顯。
如果大家不喜歡默認(rèn)的紅色以及~0.15的不透明度,我還為不透明度及顏色添加了簡單的靜態(tài)屬性設(shè)置選項,希望能讓各位獲得自己理想中的方形單元效果。在運行過程中,可見屬性不會顯示出來,但請大家注意,只要網(wǎng)格本身仍然存在于可視化元素列表當(dāng)中,就會占用對應(yīng)的性能資源(因此請務(wù)必在應(yīng)用程序的發(fā)布版本中把網(wǎng)格去掉,否則會造成毫無意義的資源浪費)。
源代碼
我已經(jīng)在NuGet上發(fā)布過源文件——這應(yīng)該是大家在自己的項目中使用這款小成品的最佳方式。如果今后我做出任何修正或添加某些功能,各位也將會在NuGet網(wǎng)站上及時找到最新版本。
◆確保自己已經(jīng)安裝了NuGet(http://www.nuget.org/)
◆使用控制臺或軟件包管理器安裝該軟件包,我把它命名為MetroGridHelper
PM> Install-Package MetroGridHelper
當(dāng)然,大家也可以將這部分源代碼在項目中整理成一個全新的文件,MetroGridHelper.cs:
- // (c) Copyright Microsoft Corporation.
 - // This source is subject to the Microsoft Public License (Ms-PL).
 - // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 - // All other rights reserved.
 - using System.Collections.Generic;
 - using System.Diagnostics;
 - using System.Windows.Controls;
 - using System.Windows.Media;
 - using System.Windows.Shapes;
 - namespace System.Windows
 - {
 - /// <summary>
 - /// A utility class that overlays a designer-friendly grid on top of the
 - /// application frame, for use similar to the performance counters in
 - /// App.xaml.cs. The color and opacity are configurable. The grid contains
 - /// a number of squares that are 24x24, offset with 12px gutters, and all
 - /// 24px away from the edge of the device.
 - /// </summary>
 - public static class MetroGridHelper
 - {
 - private static bool _visible;
 - private static double _opacity = 0.15;
 - private static Color _color = Colors.Red;
 - private static List<Rectangle> _squares;
 - private static Grid _grid;
 - /// <summary>
 - /// Gets or sets a value indicating whether the designer grid is
 - /// visible on top of the application's frame.
 - /// </summary>
 - public static bool IsVisible
 - {
 - get
 - {
 - return _visible;
 - }
 - set
 - {
 - _visible = value;
 - UpdateGrid();
 - }
 - }
 - /// <summary>
 - /// Gets or sets the color to use for the grid's squares.
 - /// </summary>
 - public static Color Color
 - {
 - get { return _color; }
 - set
 - {
 - _color = value;
 - UpdateGrid();
 - }
 - }
 - /// <summary>
 - /// Gets or sets a value indicating the opacity for the grid's squares.
 - /// </summary>
 - public static double Opacity
 - {
 - get { return _opacity; }
 - set
 - {
 - _opacity = value;
 - UpdateGrid();
 - }
 - }
 - /// <summary>
 - /// Updates the grid (if it already has been created) or initializes it
 - /// otherwise.
 - /// </summary>
 - private static void UpdateGrid()
 - {
 - if (_squares != null)
 - {
 - var brush = new SolidColorBrush(_color);
 - foreach (var square in _squares)
 - {
 - square.Fill = brush;
 - }
 - if (_grid != null)
 - {
 - _grid.Visibility = _visible ? Visibility.Visible : Visibility.Collapsed;
 - _grid.Opacity = _opacity;
 - }
 - }
 - else
 - {
 - BuildGrid();
 - }
 - }
 - /// <summary>
 - /// Builds the grid.
 - /// </summary>
 - private static void BuildGrid()
 - {
 - _squares = new List<Rectangle>();
 - var frame = Application.Current.RootVisual as Frame;
 - if (frame == null || VisualTreeHelper.GetChildrenCount(frame) == 0)
 - {
 - Deployment.Current.Dispatcher.BeginInvoke(BuildGrid);
 - return;
 - }
 - var child = VisualTreeHelper.GetChild(frame, 0);
 - var childAsBorder = child as Border;
 - var childAsGrid = child as Grid;
 - if (childAsBorder != null)
 - {
 - // Not a pretty way to control the root visual, but I did not
 - // want to implement using a popup.
 - var content = childAsBorder.Child;
 - if (content == null)
 - {
 - Deployment.Current.Dispatcher.BeginInvoke(BuildGrid);
 - return;
 - }
 - childAsBorder.Child = null;
 - Deployment.Current.Dispatcher.BeginInvoke(() =>
 - {
 - Grid newGrid = new Grid();
 - childAsBorder.Child = newGrid;
 - newGrid.Children.Add(content);
 - PrepareGrid(frame, newGrid);
 - });
 - }
 - else if (childAsGrid != null)
 - {
 - PrepareGrid(frame, childAsGrid);
 - }
 - else
 - {
 - Debug.WriteLine("Dear developer:");
 - Debug.WriteLine("Unfortunately the design overlay feature requires that the root frame visual");
 - Debug.WriteLine("be a Border or a Grid. So the overlay grid just isn't going to happen.");
 - return;
 - }
 - }
 - /// <summary>
 - /// Does the actual work of preparing the grid once the parent frame is
 - /// in the visual tree and we have a Grid instance to work with for
 - /// placing the chilren.
 - /// </summary>
 - /// <param name="frame">The phone application frame.</param>
 - /// <param name="parent">The parent grid to insert the sub-grid into.</param>
 - private static void PrepareGrid(Frame frame, Grid parent)
 - {
 - var brush = new SolidColorBrush(_color);
 - _grid = new Grid();
 - _grid.IsHitTestVisible = false;
 - // To support both orientations, unfortunately more visuals need to
 - // be used. An alternate implementation would be to react to the
 - // orientation change event and re-draw/remove squares.
 - double width = frame.ActualWidth;
 - double height = frame.ActualHeight;
 - double max = Math.Max(width, height);
 - for (int x = 24; x < /*width*/ max; x += 37)
 - {
 - for (int y = 24; y < /*height*/ max; y += 37)
 - {
 - var rect = new Rectangle
 - {
 - Width = 25,
 - Height = 25,
 - VerticalAlignment = System.Windows.VerticalAlignment.Top,
 - HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
 - Margin = new Thickness(x, y, 0, 0),
 - IsHitTestVisible = false,
 - Fill = brush,
 - };
 - _grid.Children.Add(rect);
 - _squares.Add(rect);
 - }
 - }
 - _grid.Visibility = _visible ? Visibility.Visible : Visibility.Collapsed;
 - _grid.Opacity = _opacity;
 - // For performance reasons a single surface should ideally be used
 - // for the grid.
 - _grid.CacheMode = new BitmapCache();
 - // Places the grid into the visual tree. It is never removed once
 - // being added.
 - parent.Children.Add(_grid);
 - }
 - }
 - }
 
原文鏈接:http://www.jeff.wilcox.name/2011/10/metrogridhelper/ 核子可樂 譯
















 
 
 






 
 
 
 