macos_ui

repository·dev·Indexed 24 days ago

https://github.com/macosui/macos_ui

A Flutter library providing widgets and themes that implement the macOS design language. It includes components such as MacosWindow, MacosScaffold, Sidebars, ToolBars, and various native-looking controls like MacosTextField, MacosPopupButton, and MacosSwitch to help developers build native-looking macOS applications.

Tokens
16.4K
Snippets
35
Records
61
Agent score
80%

What's inside macos_ui

  1. Implement a macOS-style layout with MacosWindow

    dev

    MacosWindow is the fundamental frame for a macOS-style layout. It supports a Sidebar on the left, an optional TitleBar at the top, and typically uses a MacosScaffold to fill the remaining area.

    To toggle the sidebar, use MacosWindowScope.of(context).toggleSidebar().

    Important: You must wrap your MacosScaffold in a Builder widget for the sidebar toggle to function correctly.

  2. Use MacosSegmentedControl for navigation tabs

    dev
    A MacosSegmentedControl displays navigational tabs in a horizontal group. It is most commonly used by MacosTabView to manage tab navigation. When using MacosTabView, you do not need to manually specify a MacosSegmentedControl as the tab view builds one automatically.
  3. Platform Compatibility and Limitations

    dev

    While macos_ui technically works on any platform supported by Flutter, it is optimized for macOS. Support for non-macOS platforms is not guaranteed.

    Certain features rely on native code and will not work on platforms other than macOS:

    • Anything related to macos_window_utils
    • The MacosColors.controlAccentColor() function
    • The MacosColorWell widget
  4. Use MacosScaffold for page content

    dev

    MacosScaffold acts as the main content area (a "page"). It features a toolbar property and a children property. The children property accepts a ContentArea widget and multiple ResizablePane widgets.

    Navigation Tip: To ensure navigation or routes stay within the scaffold area rather than covering the entire window, wrap the MacosScaffold in a CupertinoTabView. When pushing a route outside of a scaffold wrapped in a CupertinoTabView, use the root navigator: Navigator.of(context, rootNavigator: true).

  5. Configure Flutter environment for macos_ui

    dev

    To ensure a smooth development experience, follow these environment requirements:

    1. Flutter Channel: Use the stable channel.
    2. Flutter Version: Starting with version 2.2.0+1, macos_ui requires Flutter 3.35.0 or higher. If you use an older version, you will only be able to use macos_ui version 2.2.0.
  6. Customize the iOS launch screen assets

    dev

    To change the appearance of the launch screen on iOS, you must replace the image files located in the example/ios/Runner/Assets.xcassets/LaunchImage.imageset/ directory with your own assets.

    Alternatively, you can manage these assets using Xcode:

    1. Open your Flutter project's iOS workspace by running open ios/Runner.xcworkspace in your terminal.
    2. In the Xcode Project Navigator, navigate to Runner/Assets.xcassets.
    3. Drag and drop your desired images into the asset catalog to replace the existing ones.
    open ios/Runner.xcworkspace
  7. Configure macos_window_utils for older macOS versions

    dev

    If targeting macOS Monterey or earlier, you must manually configure MainFlutterWindow.swift to ensure the macos_window_utils plugin (a dependency of macos_ui) works correctly.

    1. Open macos/Runner.xcworkspace in Xcode.
    2. Locate and open MainFlutterWindow.swift.
    3. Add import macos_window_utils at the top.
    4. Replace the code above super.awakeFromNib() with the initialization logic for MacOSWindowUtilsViewController and MainFlutterWindowManipulator.
    import Cocoa
    import FlutterMacOS
    import macos_window_utils
    
    class MainFlutterWindow: NSWindow {
      override func awakeFromNib() {
        let windowFrame = self.frame
        let macOSWindowUtilsViewController = MacOSWindowUtilsViewController()
        self.contentViewController = macOSWindowUtilsViewController
        self.setFrame(windowFrame, display: true)
    
        /* Initialize the macos_window_utils plugin */
        MainFlutterWindowManipulator.start(mainFlutterWindow: self)
    
        RegisterGeneratedPlugins(registry: macOSWindowUtilsViewController.flutterViewController)
    
        super.awakeFromNib()
      }
    }
  8. Enable the Modern Window Look (macOS 11+)

    dev

    To achieve the Big Sur (macOS 11) look, macos_ui uses macos_window_utils. This requires a minimum macOS deployment target of 10.14.6.

    1. Set Deployment Target

    Via Xcode: Open macos/Runner.xcworkspace, go to Runner.xcodeproj > Info > Deployment Target, and set macOS Deployment Target to 10.14.6 or higher.

    Via CocoaPods: In your macos/Podfile, set the minimum deployment version:

    platform :osx, '10.14.6'

    2. Configure the Window in main()

    Initialize macos_window_utils in your main() function. Use NSWindowToolbarStyle.expanded if you are using a TitleBar to ensure window controls (close, minimize, zoom) align correctly. For all other cases, use NSWindowToolbarStyle.unified.

    /// This method initializes macos_window_utils and styles the window.
    Future<void> _configureMacosWindowUtils() async {
      const config = MacosWindowUtilsConfig(
        toolbarStyle: NSWindowToolbarStyle.expanded,
      );
      await config.apply();
    }
    
    void main() async {
      await _configureMacosWindowUtils();
    
      runApp(const YourAppHere());
    }
  9. How MacosScrollbarTheme and MacosTheme interact

    dev

    The macos_ui package provides two ways to manage scrollbar themes:

    1. Global Theme: You can specify a scrollbarTheme within your MacosThemeData to set a default for the entire application.
    2. Local Override: You can wrap a specific part of your widget tree with a MacosScrollbarTheme to override the global settings for that subtree.

    When calling MacosScrollbarTheme.of(context), the system first looks for the nearest MacosScrollbarTheme ancestor. If none exists, it retrieves the scrollbarTheme from the MacosTheme.of(context).

  10. Avoid popup overflow issues with window resizing

    dev

    Because Flutter does not allow UI elements to overflow the window bounds, popups are constrained to the available space.

    Best Practice: If you use widgets that create popups in your toolbar (such as ToolBarPopupButton), avoid allowing the application window to be resized below the height of your tallest popup to prevent layout issues.

  11. Add a Sidebar to MacosWindow

    dev

    Sidebars enable app navigation. You can place a sidebar on the left using the sidebar property or on the right using the endSidebar property of MacosWindow.

    Example of a left sidebar with SidebarItems:

    int pageIndex = 0;
    
    ...
    
    MacosWindow(
      sidebar: Sidebar(
        minWidth: 200,
        builder: (context, scrollController) {
          return SidebarItems(
            currentIndex: pageIndex,
            scrollController: scrollController,
            itemSize: SidebarItemSize.large,
            onChanged: (i) {
              setState(() => pageIndex = i);
            },
            items: const [
              SidebarItem(
                label: Text('Page One'),
              ),
              SidebarItem(
                label: Text('Page Two'),
              ),
            ],
          );
        },
      ),
      endSidebar: Sidebar(
        startWidth: 200,
        minWidth: 200,
        maxWidth: 300,
        shownByDefault: false,
        builder: (context, _) {
          return const Center(
            child: Text('End Sidebar'),
          );
        },
      ),
    ),
  12. Use PushButton for standard actions

    dev

    The PushButton is the standard macOS button type. It contains text and is typically used to trigger actions like opening windows or dialogs.

    Note: PushButton currently only supports text-only styling. For icon-only buttons, use MacosIconButton instead.

    PushButton(
      child: Text('button'),
      controlSize: ControlSize.regular,
      onPressed: () {
        print('button pressed');
      },
    ),