F#:Silverlight中的打字机效果

时间:2009-11-15 01:23:05

标签: silverlight f# functional-programming

我最近使用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

1 个答案:

答案 0 :(得分:2)

唯一突然出现在我身上的是重复的StoryBoard代码。使用letStoryBoardDoubleAnimationstring创建本地obj函数定义并缩小{{1}的逻辑可能是有意义的每次调用一次,{},ScaleXScaleYX动画。