패키지, 저장소 및 앱 카테고리 검색

easy_sidemenu 표지
패키지 상세v1.0.0

easy_sidemenu

Flutter에서 사용하기 쉬운 사이드 메뉴(내비게이션 레일)이며, 탐색에 사용할 수 있습니다

AndroidiOSWebmacOSWindowsLinux
30일 다운로드
2.1만
좋아요
459
Pub 점수
160

패키지 설치

flutter pub add easy_sidemenu

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

EasySideMenu는 반응형 네비게이션 인터페이스를 구축하기 위해 간단하고 사용자 정의 가능한 사이드 메뉴(네비게이션 레일)를 제공하는 Flutter 패키지입니다. Android, iOS, Web, macOS, Windows, Linux 등 여러 플랫폼을 지원합니다. 사용이 쉬운 설계로 개발자가 최소한의 설정으로 네비게이션 레일을 빠르게 구현할 수 있게 해주며, 다양한 기기에서 일관되고 접근성 있는 네비게이션을 필요로 하는 앱에 적합합니다. 이 패키지는 pub.dev를 통해 Flutter 프로젝트에 원활하게 통합될 수 있습니다.

사용 사례

  • 모바일 앱 탐색
  • 웹 대시보드 레이아웃
  • 데스크톱 애플리케이션 탐색
  • 반응형 UI 디자인
  • 크로스 플랫폼 탐색
  • 사용자 정의 가능한 사이드바 메뉴

주요 기능

  • 간단한 API 통합
  • 반응형 레이아웃 지원
  • 사용자 정의 메뉴 항목
  • 플랫폼에 관계없는 설계
  • 내장 애니메이션
  • 다크 모드를 지원합니다

적합한 대상

  • 초보자 플러터 개발자
  • 크로스 플랫폼 앱 빌더
  • UI 중심 개발자
  • 대시보드 및 관리 패널 제작자
  • 일관된 탐색이 필요한 앱

고려 사항

  • 기본 스타일링을 넘어서는 사용자 정의가 제한적입니다
  • 복잡한 디자인을 위해 추가 스타일링이 필요할 수 있습니다
  • 매우 큰 메뉴 항목 목록에 최적화되지 않음
  • 업데이트를 위해 외부 GitHub 저장소에 의존합니다

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

Easy Sidemenu

logo

License Pub Version GitHub repo size

A highly customisable side navigation menu for Flutter. Supports Material 3 theming, glassmorphism, floating card panels, expansion items, badges, and responsive auto-collapse — with zero external dependencies.


Screenshots

Open Compact
Open Compact
Auto
Auto

Live demo

https://jamalianpour.github.io/easy_sidemenu


Getting started

Add the dependency:

dependencies:
  easy_sidemenu: ^1.0.0
import 'package:easy_sidemenu/easy_sidemenu.dart';

Basic usage

import 'package:easy_sidemenu/easy_sidemenu.dart';
import 'package:flutter/material.dart';

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _controller = SideMenuController();
  final _pageController = PageController();

  @override
  void initState() {
    super.initState();
    // Mirror selections to a PageView (or any router)
    _controller.addListener(() {
      _pageController.jumpToPage(_controller.currentIndex);
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          SideMenu(
            controller: _controller,
            items: [
              SideMenuItem(
                title: 'Dashboard',
                icon: const Icon(Icons.dashboard_rounded),
                onTap: (index, controller) => controller.goTo(index),
              ),
              SideMenuItem(
                title: 'Settings',
                icon: const Icon(Icons.settings_rounded),
                onTap: (index, controller) => controller.goTo(index),
              ),
            ],
          ),
          Expanded(
            child: PageView(
              controller: _pageController,
              physics: const NeverScrollableScrollPhysics(),
              children: const [
                Center(child: Text('Dashboard')),
                Center(child: Text('Settings')),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

Items

SideMenuItem
SideMenuItem(
  title: 'Dashboard',
  icon: const Icon(Icons.dashboard_rounded),
  // Optional badge overlaid on the icon
  badge: const Text('3', style: TextStyle(color: Colors.white, fontSize: 10)),
  // Tooltip shown in compact mode
  tooltipContent: 'Dashboard',
  // Widget shown at the trailing edge in open mode
  trailing: const Icon(Icons.chevron_right, size: 16),
  onTap: (index, controller) => controller.goTo(index),
),
Custom builder

Replace the default layout entirely for a single item:

SideMenuItem(
  builder: (context, displayMode) {
    return const Divider(height: 24, indent: 8, endIndent: 8);
  },
),
SideMenuExpansionItem
SideMenuExpansionItem(
  title: 'Projects',
  icon: const Icon(Icons.folder_rounded),
  initiallyExpanded: false,
  children: [
    SideMenuItem(
      title: 'Active',
      icon: const Icon(Icons.circle, size: 10),
      onTap: (index, controller) => controller.goTo(index),
    ),
    SideMenuItem(
      title: 'Archived',
      icon: const Icon(Icons.circle_outlined, size: 10),
      onTap: (index, controller) => controller.goTo(index),
    ),
  ],
),

Controller

SideMenuController extends ChangeNotifier:

final controller = SideMenuController(initialIndex: 0);

// Navigate to an item
controller.goTo(2);

// Read the current index
print(controller.currentIndex);

// Listen for changes
controller.addListener(() {
  print('Selected: ${controller.currentIndex}');
});

// Always dispose
controller.dispose();

Theming

SideMenuThemeData is a Material 3 ThemeExtension. Register it once for the whole app, or pass it directly to a single SideMenu.

App-wide (recommended)
MaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
    useMaterial3: true,
    extensions: const [
      SideMenuThemeData(
        openWidth: 260,
        selectedColor: Color(0xFF2563EB),
        selectedIconColor: Colors.white,
        selectedTitleStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.w600),
      ),
    ],
  ),
)
Per-widget override
SideMenu(
  controller: controller,
  theme: const SideMenuThemeData(
    displayMode: SideMenuDisplayMode.compact,
    compactWidth: 72,
  ),
  items: [...],
)
SideMenuThemeData properties
Property Type Default Description
displayMode SideMenuDisplayMode auto auto / open / compact
openWidth double 300 Width in open mode
compactWidth double 70 Width in compact mode
collapseWidth double 600 Screen width at which auto switches to compact
menuDecoration BoxDecoration? null Full decoration for the menu container (overrides backgroundColor)
backdropSigma double? null Blur sigma for glassmorphism — wraps the menu in BackdropFilter
backgroundColor Color? ColorScheme.surface Menu background (ignored when menuDecoration is set)
selectedItemDecoration BoxDecoration? null Full decoration for the selected item (overrides selectedColor)
selectedColor Color? ColorScheme.primaryContainer Selected item highlight
hoverColor Color? onSurface 8% Hover highlight
selectedHoverColor Color? primaryContainer 80% Hover colour when item is also selected
selectedIconColor Color? ColorScheme.onPrimaryContainer Icon colour when selected
unselectedIconColor Color? ColorScheme.onSurfaceVariant Icon colour when unselected
iconSize double 24 Icon size
selectedTitleStyle TextStyle? labelLarge / onPrimaryContainer Title text style when selected
unselectedTitleStyle TextStyle? labelLarge / onSurfaceVariant Title text style when unselected
itemHeight double 50 Item row height
itemBorderRadius BorderRadius circular(8) Item corner radius
itemOuterPadding EdgeInsetsGeometry symmetric(h: 5) Padding around each item
itemInnerSpacing double 8 Spacing between icon and title
showTooltip bool true Show item title as tooltip in compact mode
showHamburger bool false Show a hamburger button that collapses the menu
toggleColor Color? onSurfaceVariant Expand/collapse toggle icon colour
expansionArrowColor Color? onSurfaceVariant Expansion arrow in collapsed state
expansionArrowOpenColor Color? ColorScheme.primary Expansion arrow in open state
SideMenu properties
Property Type Default Description
controller SideMenuController required Manages the selected index
items List<SideMenuItemBase> required Items to display
theme SideMenuThemeData? null Per-widget theme override
title Widget? null Widget shown above items
footer Widget? null Widget pinned to the bottom
alwaysShowFooter bool false Keep footer visible in compact mode
showToggle bool false Show collapse/expand toggle button
collapseWidth double 600 Screen width threshold for auto mode
displayModeToggleDuration Duration 350 ms Open ↔ compact animation duration
onDisplayModeChanged ValueChanged<SideMenuDisplayMode>? null Called when display mode changes

Advanced customisation

Gradient sidebar
SideMenu(
  controller: controller,
  theme: const SideMenuThemeData(
    menuDecoration: BoxDecoration(
      gradient: LinearGradient(
        colors: [Color(0xFF667EEA), Color(0xFF764BA2)],
        begin: Alignment.topCenter,
        end: Alignment.bottomCenter,
      ),
    ),
    selectedColor: Color(0x33FFFFFF),
    selectedIconColor: Colors.white,
  ),
  items: [...],
)
Left-border selected indicator (Minimal style)
SideMenu(
  controller: controller,
  theme: const SideMenuThemeData(
    selectedItemDecoration: BoxDecoration(
      color: Color(0xFFEFF6FF),
      border: Border(left: BorderSide(color: Color(0xFF2563EB), width: 3)),
    ),
    itemBorderRadius: BorderRadius.zero,
    itemOuterPadding: EdgeInsets.zero,
  ),
  items: [...],
)
Glassmorphism

Requires a backdropSigma and a semi-transparent menuDecoration. Place the SideMenu inside a widget that has a visible background (image, gradient) behind it.

// 1. Wrap the whole layout in a gradient container
Container(
  decoration: const BoxDecoration(
    gradient: LinearGradient(
      colors: [Color(0xFF1A1A2E), Color(0xFF0F3460)],
    ),
  ),
  child: Row(
    children: [
      // 2. The SideMenu renders as a frosted panel
      SideMenu(
        controller: controller,
        theme: SideMenuThemeData(
          backdropSigma: 18,
          menuDecoration: BoxDecoration(
            color: Colors.white.withValues(alpha: 0.15),
            border: Border(
              right: BorderSide(color: Colors.white.withValues(alpha: 0.25)),
            ),
          ),
          selectedIconColor: Colors.white,
          unselectedIconColor: Colors.white70,
        ),
        items: [...],
      ),
      Expanded(child: ...),
    ],
  ),
)
Floating card (rounded + shadow)

Wrap the SideMenu in a Padding and set menuDecoration with a borderRadius and boxShadow:

Row(
  children: [
    Padding(
      padding: const EdgeInsets.all(8),
      child: SideMenu(
        controller: controller,
        theme: SideMenuThemeData(
          menuDecoration: BoxDecoration(
            color: Colors.white,
            borderRadius: const BorderRadius.all(Radius.circular(16)),
            border: Border.all(color: const Color(0xFFE2E8F0)),
            boxShadow: [
              BoxShadow(
                color: Colors.black.withValues(alpha: 0.08),
                blurRadius: 24,
                offset: const Offset(4, 0),
              ),
            ],
          ),
        ),
        items: [...],
      ),
    ),
    Expanded(child: ...),
  ],
)

Migrating from v0.7

See MIGRATION.md for a complete before/after guide covering every breaking change.

Quick summary:

v0.7 v1.0
SideMenuStyle(...) SideMenuThemeData(...)
style: param on SideMenu theme: param on SideMenu
openSideMenuWidth openWidth
compactSideMenuWidth compactWidth
controller.changePage(i) controller.goTo(i)
controller.currentPage controller.currentIndex
controller.addListener((i) {...}) controller.addListener(() { use controller.currentIndex })
SideMenuItemType SideMenuItemBase
badgeContent: badge:
initialExpanded: initiallyExpanded:

Contributing

Issues and pull requests are welcome on GitHub.


License

MIT — see LICENSE for details.

카테고리

소스 저장소

이 패키지를 사용하는 프로젝트