我最近使用F#在Silverlight中实现了一个动画打字机效果。我的代码有效,但我想知道是否有人对代码可能改进的方法提出了建议。即使用Seq.iter或Seq.map来做这个是好是坏?欢迎任何意见和评论!
我还以为我会记录代码以防其他人
反馈编辑:添加了用于将动画挂钩到故事板的本地功能
let createTypewriter(text:string) =
//Controls the animation of each character
let storyboard = new Storyboard()
//This will contain every line of text
let textboard = new StackPanel(Orientation=Orientation.Vertical)
//Creates a new StackPanel to hold the words and puts it in the wrapPanel
let newWordContainer (wrapPanel:WrapPanel) =
let wordContainer = new StackPanel(Orientation=Orientation.Horizontal)
wrapPanel.Children.Add( wordContainer)
wordContainer
//Parse the entire string
let rec parseLetters letter delay wordContainer wrapPanel : Storyboard * StackPanel =
match letter with
//If there's nothing left to parse return the initialized storyboard
//and textboard
| [] -> (storyboard, textboard)
//Using pattern matching we recursively handle the current character (head)
//then rest of the characters (tail)
//Handle Spaces. If we encounter a space, we create a new horizontal
//StackPanel to put individual characters into. This new StackPanel
//is added to the wrapPanel
| head :: tail when head = ' ' ->
let newCont = newWordContainer wrapPanel
newCont.Children.Add(new TextBlock(Text=" "))
parseLetters tail (delay+1.0) newCont wrapPanel
//If we encounter a newline or a return, we want to move down to a new line.
//Thus we insert a new WrapPanel into our vertical StackPanel (textboard)
| head :: tail when head ='\n' || head = '\r' -> //Handle new lines
let newWrapPanel = new WrapPanel(MinHeight = this.FontSize)
let newCont = newWordContainer newWrapPanel
textboard.Children.Add(newWrapPanel)
parseLetters tail (delay+1.0) newCont newWrapPanel
//Letters will be placed in TextBlocks and added to horizontal StackPanels
//(wordContainer) to make words. Each TextBlock will have an animation
//controlled by the StoryBoard.
| head :: tail ->
//Create the animation transforms
let st = new ScaleTransform(ScaleX=5.0, ScaleY=5.0)
let tt = new TranslateTransform(X=(-40.0),Y=0.0)
let tg = new TransformGroup()
tg.Children.Add(st)
tg.Children.Add(tt)
//Create the TextBlock and set its transform
let tb = new TextBlock(Text=head.ToString(), Opacity=0.0, RenderTransform=tg,RenderTransformOrigin = new Point(0.5,0.5))
wordContainer.Children.Add(tb)
//Create the DoubleAnimations that specify how the text will animate,
//Darn Nullable types make this really ugly =/
let bt = TimeSpan.FromMilliseconds(1000.0 + delay * 30.0);
let duration = new Duration(TimeSpan.FromSeconds(0.1))
let opacityDA = new DoubleAnimation(From=Nullable(0.0), To=Nullable(1.0), Duration=duration, BeginTime=Nullable(bt))
let translateDA = new DoubleAnimation( From=Nullable(-40.0), To=Nullable(0.0), Duration=duration, BeginTime=Nullable(bt))
let scaleXDA = new DoubleAnimation(From=Nullable(5.0), To=Nullable(1.0), Duration=duration, BeginTime=Nullable(bt))
let scaleYDA = new DoubleAnimation(From=Nullable(5.0), To=Nullable(1.0), Duration=duration, BeginTime=Nullable(bt))
//Create a function that will hook the animation info to the storyboard.
let addToStoryboard doubleAni obj (propName:string) =
Storyboard.SetTarget(doubleAni, obj)
Storyboard.SetTargetProperty(doubleAni, new PropertyPath(propName))
storyboard.Children.Add(doubleAni)
addToStoryboard scaleXDA st "ScaleX"
addToStoryboard scaleYDA st "ScaleY"
addToStoryboard translateDA tt "X"
addToStoryboard opacityDA tb "Opacity"
//Parse the rest of the letters
parseLetters tail (delay+1.0) wordContainer wrapPanel
//Begin the recursion over the passed in string
let wrapPanel = new WrapPanel()
textboard.Children.Add(wrapPanel)
parseLetters (Seq.toList text) 0.0 (newWordContainer wrapPanel) wrapPanel
答案 0 :(得分:2)
唯一突然出现在我身上的是重复的StoryBoard代码。使用let
,StoryBoard
,DoubleAnimation
和string
创建本地obj
函数定义并缩小{{1}的逻辑可能是有意义的每次调用一次,{},ScaleX
,ScaleY
和X
动画。