先來看看iPhone的短信界面,就當是麻豆了 ^-^。
這么簡潔美麗又大方的界面也就蘋果想的出來。
剛看到這個界面,口水就止不住啊。
擦干口水,趕緊模仿。
最初做法:
基於UserControl,自己做一個用戶控件,內含TextBolck可以實現多行顯示文本,
使用Path和Geometry將帶有小尾巴的圖形畫出來,然后再畫上光照效果,就大功
告成了。
雖然效果能做出來,但是細細想來,還是有不妥。
問題就在於,自己作的這個控件,只能顯示文字,為了要顯示圖片,還得寫一堆代碼,
太過死板,為什么就不能利用WPF的框架或特點,讓這個控件變的靈活一些,只要些
繪圖效果和控制布局的效果就OK了,至於內部包含的是文字還是圖片,就交給WPF去
完成好了。
基於此,立馬想到為TextBlock控件寫個Template,但稍稍一定神發現,用Template
完成復雜圖形的繪制有些虛無縹緲,結果放棄。
在老大的點化之下,采用Decorater。乍看之下,有點摸不着北,細細看來,發現,
Border就是從此類繼承而來,說白了就是包含一個子元素的容器,自定義的Decorater
負責繪制圖形背景,顯示的內容就交給子元素去完成。
為什么不用Border而用它,道理就是用它就足夠了,干凈。
(當然了,容器還有Panel,ContentControl,在這里用Decorater就夠了)。
主要就是用到基類的方法:
MeasureOverride:通過測量子元素來計算需要的空間的大小。
ArrangeOverride:排列子元素的顯示位置。
OnRender:自繪函數,帶小尾巴的圖形繪制就在這里了,等價於OnPaint。
最終的效果:
實現。
自定義IDecorator類:
public class iDecorator : Decorator { public iDecorator() { this.HorizontalAlignment = System.Windows.HorizontalAlignment.Right; } public bool Direction { get { return (bool)GetValue(DirectionProperty); } set { SetValue(DirectionProperty, value); } } protected override Size MeasureOverride(Size constraint) { Size result = new Size(); if (Child != null) { Child.Measure(constraint); result.Width = Child.DesiredSize.Width + padding.Left + padding.Right; result.Height = Child.DesiredSize.Height + padding.Top + padding.Bottom; if (result.Height < 35) { result.Height = 35; padding.Top = padding.Bottom = (result.Height - Child.DesiredSize.Height) / 2; } } return result; } protected override Size ArrangeOverride(Size arrangeSize) { if (Child != null) { Child.Arrange(new Rect(new Point(padding.Left, padding.Top), Child.DesiredSize)); } return arrangeSize; } protected override void OnRender(DrawingContext dc) { if (Child != null) { Geometry cg = null; Brush brush = null; Pen pen = new Pen(); pen.Brush = new SolidColorBrush(Colors.Black); pen.Thickness = 1; if (Direction) { //生成小尾巴在右側的圖形和底色 cg = CreateGeometryTailAtRight(); brush = CreateBrushTailAtRight(); } else { //生成小尾巴在左側的圖形和底色 cg = CreateGeometryTailAtLeft(); brush = CreateBrushTailAtLeft(); } dc.DrawGeometry(brush, pen, cg); //繪制光照效果 GradientStopCollection gscLight = new GradientStopCollection(); gscLight.Add(new GradientStop(Color.FromArgb(0xDA, 0xFF, 0xFF, 0xFF), 0)); gscLight.Add(new GradientStop(Color.FromArgb(0x68, 0xFF, 0xEF, 0xFF), 1)); Brush lightBrush = new LinearGradientBrush(gscLight, new Point(0, 0), new Point(0, 1)); dc.DrawRoundedRectangle(lightBrush, null, new Rect(22, 1, this.ActualWidth - 45, 20), 10, 10); }
//省略部分代碼。。。 public static void OnDirectionPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var self = d as iDecorator; self.HorizontalAlignment = (bool)e.NewValue ? HorizontalAlignment.Right : HorizontalAlignment.Left; } private Thickness padding = new Thickness(25, 6, 25, 6); public static readonly DependencyProperty DirectionProperty = DependencyProperty.Register("Direction", typeof(bool), typeof(iDecorator), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender, OnDirectionPropertyChangedCallback)); }
調用處:
短信框的小尾巴在右側:
<local:iDecorator HorizontalAlignment="Right" Direction="True"> <TextBlock MaxWidth="200" Foreground="Black" TextWrapping="Wrap">前兩天去哪兒了,聽說去北京了???</TextBlock> </local:iDecorator>
短信框的小尾巴在左側:
就是把Direction(方向)設成False即可。
<local:iDecorator HorizontalAlignment="Right" Direction="False"> <TextBlock MaxWidth="200" Foreground="Black" TextWrapping="Wrap">前兩天去哪兒了,聽說去北京了???</TextBlock> </local:iDecorator>
調用是不是很方便,把它當成容器用就行了。
大功告成!
代碼:http://download.csdn.net/download/kongxh_1981/9161495