702 Star 6.5K Fork 1.3K

GVPSunny / SunnyUI

 / 详情

关于UIForm的窗体动画建议

已关闭
创建于  
2021-08-05 12:08

我找到了三篇文章,并且测试了一下,最佳解决因设置无边框窗体导致的动画丢失解决方案-
【1】stackoverflow-Borderless Window Using Areo Snap, Shadow, Minimize Animation, and Shake
【2】stackoverflow-FormBorderStyle.None removes the native open effect of windows 8
【3】stackoverflow-Use windows animations on borderless form

以下为伪代码

case WM_NCCALCSIZE: {
    if (是否已经打开阴影---->>m_aeroEnabled) {
        【return 0;】 //---->> m.Result = IntPtr.Zero
    } else {
        【return DefWindowProc(hwnd, msg, wparam, lparam);】 //---->> DefWndProc(m);
    }
}

此方法仍需要DWMAPI来绘制阴影,其次由于窗体没有了标题栏(都属于边框),需要自己重绘一个标题栏
正好SunnyUI需要自行重绘,免去了设置 FormBorderStyle = FormBorderStyle.None;时造成不必要动画丢失的问题
经我测试,以下VB.NET代码没有问题,可以保证 阴影开启、动画保留、无闪烁
CSkin界面库

    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case Win32.User.WM_ERASEBKGND
                m.Result = IntPtr.Zero
            Case Win32.User.WM_NCCALCSIZE
                If m_aeroEnabled Then
                    m.Result = IntPtr.Zero
                Else
                    DefWndProc(m)'如需更深层定义可重写该函数
                End If
            Case Else
                MyBase.WndProc(m)
        End Select
'''------拖拽调节大小
        If m.Msg = Win32.User.WM_NCHITTEST AndAlso WindowState = FormWindowState.Normal Then
            Dim vPoint As Point = New Point(MousePosition.X, MousePosition.Y)
            vPoint = PointToClient(vPoint)
            Dim dragSize As Integer = 5

            If vPoint.X <= dragSize Then

                If vPoint.Y <= dragSize Then
                    m.Result = CType(Win32.User.HTTOPLEFT, IntPtr)
                ElseIf vPoint.Y >= ClientSize.Height - dragSize Then
                    m.Result = CType(Win32.User.HTBOTTOMLEFT, IntPtr)
                Else
                    m.Result = CType(Win32.User.HTLEFT, IntPtr)
                End If
            ElseIf vPoint.X >= ClientSize.Width - dragSize Then

                If vPoint.Y <= dragSize Then
                    m.Result = CType(Win32.User.HTTOPRIGHT, IntPtr)
                ElseIf vPoint.Y >= ClientSize.Height - dragSize Then
                    m.Result = CType(Win32.User.HTBOTTOMRIGHT, IntPtr)
                Else
                    m.Result = CType(Win32.User.HTRIGHT, IntPtr)
                End If
            ElseIf vPoint.Y <= dragSize Then
                m.Result = CType(Win32.User.HTTOP, IntPtr)
            ElseIf vPoint.Y >= ClientSize.Height - dragSize Then
                m.Result = CType(Win32.User.HTBOTTOM, IntPtr)
            End If
            current_size = Size
        End If
'''------拖拽调节大小
        If m.Msg = Win32.User.WM_NCPAINT AndAlso m_aeroEnabled Then
            Dim v = 2
            Win32.Dwm.DwmSetWindowAttribute(Handle, 2, v, 4)
            Dim margins As Win32.Dwm.MARGINS = New Win32.Dwm.MARGINS() With {
            .bottomHeight = 1,
            .leftWidth = 1,
            .rightWidth = 1,
            .topHeight = 1
        }
            Win32.Dwm.DwmExtendFrameIntoClientArea(Handle, margins)
        End If
    End Sub

代码转换地址:https://converter.telerik.com/

我追求动画的初衷并不是为了多美观,而是尽量追求在视觉上不显得突兀,如QQ、微信等尚未适配原生API,而网易云音乐完美的保留了几乎所有的原生窗体特性(之前版本没有保留)

showdialog的窗体也可以通过继承主窗体来实现原生样式,而且就目前的UIstyle,个人觉得不够深度自定义(毕竟您希望如果是高度自定义请自行改源码),不过网上为了扁平化上循环draw png的都有,就是为了搞个阴影,很多人都不知道有dwmapi,且绝大多数需要自行设置标题栏,如果您能够解决,我相信任何人更愿意去nuget download,而不是clone code,sunnyUI是后来者,应该取cskin的优点而不是保留无边框

其次我在重写最大化最小化和还原上遇到了没有对应事件的问题,重写标题栏虽然没有必要,但是至少弄个图片上去吧,三个按钮可选择添加三种状态的图片,可以自定义按钮尺寸,没有就用默认的,因为在我调整完全局配色时发现右上角三个按钮底色还是蓝色,如果不愿重写,能否留出个接口以便我自行重写标题栏?非常感谢

另外CSkin的关键技术今天用de4dot反编译出来了:大量的重写wndproc,而不是gdi,说明是大量重写不是重绘,能够省下很多性能,而且重写底层更容易实现,而不是重绘了发现没变化,只能启用userpaint,然后还得写CreateParams来屏蔽闪烁。不过sunnyUI现在已经很不错了,win32的DeviceIoControl类型能写对的全网都没几个人,您类型写对了,我今天测试发现已经可以加载驱动了,希望能够改进相关功能。

评论 (2)

MIAIONE 创建了任务
MIAIONE 关联仓库设置为Sunny/SunnyUI
展开全部操作日志

写的好多,挺好的,消化不了,建议修改后提交PR

日后陆续添加吧,我就是因为解决不了其中某些bug才来发的issue

Sunny 任务状态待办的 修改为已取消

登录 后才可以发表评论

状态
负责人
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
参与者(2)
416720 yhuse 1585144111
C#
1
https://gitee.com/yhuse/SunnyUI.git
git@gitee.com:yhuse/SunnyUI.git
yhuse
SunnyUI
SunnyUI

搜索帮助