2009-11-15 72 views
2

我最近在使用F#的Silverlight中实现了动画打字机效果。我的代码有效,但我想看看是否有人对代码的改进方式提出建议。即用Seq.iter或Seq.map来做它是好的还是坏主意?欢迎任何意见和评论!F#:Silverlight中的打字机效果

我还以为我会记录代码的情况下,它可能会帮助别人

反馈编辑:增加了对挂钩动画,在跳出的故事板

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 
+6

不要欺负自己:你只是想炫耀一些很酷的代码! ;) – RCIX 2009-11-15 01:52:28

+0

我没有测试它,但就格式化/样式而言,代码本身看起来相当不错。 – bcat 2009-11-15 02:10:31

+0

我写了一些C#代码来做到这一点,即使逻辑非常相似,它大约是它的两倍!我不能返回一个元组:( – rysama 2009-11-15 09:53:56

回答

2

唯一的本地功能我是重复的StoryBoard代码。这可能是有道理创建一个本地let函数定义采取StoryBoardDoubleAnimationstring,并且obj和冷凝为ScaleXScaleYX逻辑,并Opacity动画,每一个电话。

+0

)感谢您的反馈,我添加了let函数,现在看起来好多了,我并不觉得它将故事板作为参数传递,因为它被定义为顶部的闭包。 再次感谢。 – rysama 2009-11-15 09:50:56