是否可以使用标准控件生成动画过渡?

问题描述 投票:0回答:1

是否可以使用 VB.NET 语言中的标准 WinForms 控件制作动画,如 Bunifu 生成的过渡?

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        PanelForm.Visible = False
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        BunifuTransition1.Show(PanelForm)
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        BunifuTransition1.Hide(PanelForm)
    End Sub
End Class

vb.net winforms animation transition bunifu
1个回答
0
投票

要向窗口(控件是窗口)添加一些动画效果,可以使用 Win32 AnimateWindow 函数。
此函数允许生成一些预定义的效果:滚动、滑动、折叠或展开以及 alpha 混合淡入淡出(但只能应用于顶级窗口)。

它缺少任何缩放窗口内容的效果,如问题所示。
我在扩展方法

Animate()
中添加了这个缺失的效果(以及已经支持的效果),该方法应用于从 Control 派生的所有类。

例如,要为面板(及其承载的控件)设置动画,请编写:

SomePanel.Animate(AnimationMode.OpenScale, 500)

添加持续 500 毫秒的开场动画。或者,例如,

SomePanel.Animate(AnimationMode.CloseScale, 500)

添加具有相同持续时间的结束动画。
尝试您可以选择的其他效果,设置不同的

AnimationMode

这就是它的工作原理:

GIF动画有点迟缓


将此模块添加到任何 WinForms 项目中。

Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices

Module ExtensionMethods
    ''' <summary>
    ''' Add opening or closing effects to a Control
    ''' </summary>
    ''' <param name="window">The Control to animate</param>
    ''' <param name="mode">The animation effect</param>
    ''' <param name="animationSpeed">The overall time, in milliseconds, of the animation</param>
    <Extension()>
    Public Sub Animate(window As Control, mode As AnimationMode, animationSpeed As Integer)
        If mode.HasFlag(AnimationMode.OpenScale) OrElse mode.HasFlag(AnimationMode.CloseScale) Then
            AnimateScale(window, mode, animationSpeed)
        Else
            window.Show()
            If Not mode.HasFlag(AnimationMode.Hide) Then window.Hide()
            AnimateWindow(window.Handle, CType(animationSpeed, UInteger), mode)
            If Not mode.HasFlag(AnimationMode.Hide) Then window.Show()
        End If
    End Sub

    Private animateBitmap As Bitmap = Nothing
    Private animateBitmapBoounds As Rectangle = Rectangle.Empty

    Private Sub AnimateScale(window As Control, mode As AnimationMode, Optional animationSpeed As Integer = 200)
        Dim steps = 10
        If animationSpeed < 200 Then animationSpeed = 200
        Dim timerSteps = animationSpeed \ steps
        Dim animationFrames As List(Of Bitmap) = Nothing

        Using bmpSource = New Bitmap(window.Width, window.Height, PixelFormat.Format32bppArgb)
            window.Show()
            window.DrawToBitmap(bmpSource, New Rectangle(Point.Empty, window.Size))
            window.Hide()
            animationFrames = GetAnimationFrames(steps, bmpSource, mode.HasFlag(AnimationMode.CloseScale))
        End Using

        Dim windowParent = If(window.Parent Is Nothing, window, window.Parent)
        animateBitmapBoounds = window.Bounds
        Dim timer = New System.Windows.Forms.Timer() With {.Interval = timerSteps}
        AddHandler timer.Tick,
        Sub()
            If steps < 0 Then
                timer.Stop()
                RemoveHandler windowParent.Paint, AddressOf AnimateWindowParent
                animationFrames.ForEach(Sub(img) img.Dispose())
                animationFrames = Nothing
                animateBitmap = Nothing
                timer.Dispose()
            Else
                animateBitmap = animationFrames(steps)
                windowParent.Invalidate(animateBitmapBoounds)
                If steps = 0 AndAlso mode.HasFlag(AnimationMode.OpenScale) Then window.Show()
            End If
            steps -= 1
        End Sub
        AddHandler windowParent.Paint, AddressOf AnimateWindowParent
        window.Hide()
        timer.Start()
    End Sub

    Private Function GetAnimationFrames(framesCount As Integer, sourceImage As Image, collapse As Boolean) As List(Of Bitmap)
        Dim animationFrames As New List(Of Bitmap)(framesCount)
        Dim scaleWidth = sourceImage.Width \ framesCount
        Dim scaleHeight = sourceImage.Height \ framesCount

        For frame As Integer = 1 To framesCount
            Dim imageSize = New Size(sourceImage.Width - frame * scaleWidth, sourceImage.Height - frame * scaleHeight)
            Dim imagePos = New Point((sourceImage.Width - imageSize.Width) \ 2, (sourceImage.Height - imageSize.Height) \ 2)
            Dim imageFrame = New Bitmap(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb)
            Using g = Graphics.FromImage(imageFrame)
                g.DrawImage(sourceImage, New RectangleF(imagePos, imageSize),
                            sourceImage.GetBounds(GraphicsUnit.Pixel), GraphicsUnit.Pixel)
                If collapse Then
                    animationFrames.Insert(0, imageFrame)
                    If frame = framesCount Then animationFrames.Insert(0, New Bitmap(2, 2))
                Else
                    animationFrames.Add(imageFrame)
                    If frame = framesCount Then animationFrames.Add(New Bitmap(2, 2))
                End If
            End Using
        Next
        Return animationFrames
    End Function

    Private Sub AnimateWindowParent(sender As Object, e As PaintEventArgs)
        If animateBitmap Is Nothing Then Return
        e.Graphics.DrawImage(animateBitmap, animateBitmapBoounds)
    End Sub

    <Flags()>
    Public Enum AnimationMode As UInteger
        CloseCentered = AW_CENTER Or AW_HIDE
        CloseDownwards = AW_VER_POSITIVE Or AW_HOR_POSITIVE Or AW_HIDE
        CloseUpwards = AW_VER_NEGATIVE Or AW_HOR_NEGATIVE Or AW_HIDE
        OpenCentered = AW_CENTER
        OpenDownwards = AW_HOR_POSITIVE Or AW_VER_POSITIVE
        OpenUpwards = AW_HOR_NEGATIVE Or AW_VER_NEGATIVE
        OpenScale = &H20
        CloseScale = &H40 Or Hide
        SlideToRight = AW_SLIDE Or AW_HOR_POSITIVE
        SlideToLeft = AW_SLIDE Or AW_HOR_NEGATIVE
        SlideDownwards = AW_SLIDE Or AW_VER_POSITIVE
        SlideUpwards = AW_SLIDE Or AW_VER_NEGATIVE
        Hide = AW_HIDE
    End Enum

    Private Const AW_HOR_POSITIVE As UInteger = &H1
    Private Const AW_HOR_NEGATIVE As UInteger = &H2
    Private Const AW_VER_POSITIVE As UInteger = &H4
    Private Const AW_VER_NEGATIVE As UInteger = &H8
    Private Const AW_CENTER As UInteger = &H10
    Private Const AW_HIDE As UInteger = &H10000
    Private Const AW_ACTIVATE As UInteger = &H20000
    Private Const AW_SLIDE As UInteger = &H40000
    Private Const AW_BLEND As UInteger = &H80000

    <DllImport("user32.dll", SetLastError:=True)>
    Private Function AnimateWindow(hwnd As IntPtr, time As UInteger, flags As AnimationMode) As Boolean
    End Function
End Module
© www.soinside.com 2019 - 2024. All rights reserved.