2009-11-15 78 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