draggable_overlay_window 1.0.0 copy "draggable_overlay_window: ^1.0.0" to clipboard
draggable_overlay_window: ^1.0.0 copied to clipboard

A highly customizable draggable and resizable overlay window widget for Flutter. Perfect for creating floating panels, tool windows, and multi-window interfaces.

example/lib/main.dart

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Draggable Overlay Window Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    // Basta envolver com WindowManagerScope!
    return WindowManagerScope(
      // Callback global quando qualquer janela é fechada
      onWindowClosed: (id) {
        debugPrint('Janela fechada: $id');
      },
      // Callback global quando qualquer janela ganha foco
      onWindowFocused: (id) {
        debugPrint('Janela em foco: $id');
      },
      child: Scaffold(
        backgroundColor: Colors.grey[100],
        body: ListView(
          padding: const EdgeInsets.all(20),
          children: [
            const SizedBox(height: 50),
            Text(
              'Teste de Janelas Flutuantes',
              style: Theme.of(context).textTheme.headlineMedium,
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 8),
            Text(
              'Clique em uma janela para trazê-la ao topo!',
              style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                    color: Colors.grey.shade600,
                  ),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 20),
            // Botões para abrir janelas
            const WindowButtons(),
          ],
        ),
      ),
    );
  }
}

/// Widget com os botões para abrir janelas
class WindowButtons extends StatelessWidget {
  const WindowButtons({super.key});

  @override
  Widget build(BuildContext context) {
    // Obtém o controller do WindowManagerScope
    final windows = WindowManagerScope.of(context);

    return Wrap(
      spacing: 10,
      runSpacing: 10,
      alignment: WrapAlignment.center,
      children: [
        // Janela padrão - permite múltiplas
        ElevatedButton.icon(
          icon: const Icon(Icons.window),
          label: const Text('Padrão (Multi)'),
          onPressed: () {
            windows.open(
              id: 'simple',
              unique: false, // Permite múltiplas!
              title: 'Simples',
              content: const Center(
                child: Text(
                  'Janela Padrão\nRedimensionável e Arrastável',
                  textAlign: TextAlign.center,
                ),
              ),
            );
          },
        ),

        // Perfil - única
        ElevatedButton.icon(
          icon: const Icon(Icons.person),
          label: const Text('Perfil (Único)'),
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.blue.shade100,
          ),
          onPressed: () {
            windows.open(
              id: 'profile',
              title: 'Perfil do Usuário',
              content: const UserProfileContent(),
              initialSize: const Size(350, 500),
              config: DraggableWindowConfig(
                headerBackgroundColor: Colors.blue.shade700,
                headerIconColor: Colors.white,
                enableScrolling: false,
                headerTextStyle: const TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                ),
              ),
            );
          },
        ),

        // Nota - permite múltiplas
        ElevatedButton.icon(
          icon: const Icon(Icons.sticky_note_2),
          label: const Text('Nota (Multi)'),
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.yellow.shade100,
          ),
          onPressed: () {
            windows.open(
              id: 'note',
              unique: false,
              title: 'Lembrete',
              initialSize: const Size(200, 200),
              content: Container(
                color: Colors.yellow.shade50,
                padding: const EdgeInsets.all(16),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Nota Rápida',
                      style: TextStyle(
                        fontFamily: 'cursive',
                        fontSize: 24,
                        color: Colors.grey.shade800,
                      ),
                    ),
                    const Divider(),
                    const Text('Escreva algo...'),
                  ],
                ),
              ),
              config: DraggableWindowConfig(
                windowBackgroundColor: Colors.yellow.shade50,
                headerBackgroundColor: Colors.yellow.shade700,
                borderColor: Colors.yellow.shade900,
                dividerColor: Colors.yellow.shade900,
                borderRadius: 0,
                elevation: 4,
              ),
            );
          },
        ),

        // Aviso - única
        ElevatedButton.icon(
          icon: const Icon(Icons.lock),
          label: const Text('Aviso (Único)'),
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.red.shade100,
          ),
          onPressed: () {
            windows.open(
              id: 'alert',
              title: 'Aviso Importante',
              initialSize: const Size(300, 200),
              content: const Center(
                child: Padding(
                  padding: EdgeInsets.all(16.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Icon(Icons.warning, size: 40, color: Colors.orange),
                      SizedBox(height: 10),
                      Text(
                        'Esta é uma janela de alerta fixa.\nNão pode ser redimensionada.',
                        textAlign: TextAlign.center,
                      ),
                    ],
                  ),
                ),
              ),
              config: const DraggableWindowConfig(
                resizable: false,
                borderColor: Colors.red,
                headerBackgroundColor: Colors.red,
                headerIconColor: Colors.white,
                headerTextStyle: TextStyle(color: Colors.white),
              ),
            );
          },
        ),

        // Player - única
        ElevatedButton.icon(
          icon: const Icon(Icons.music_note),
          label: const Text('Player (Único)'),
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.grey.shade300,
          ),
          onPressed: () {
            windows.open(
              id: 'player',
              title: 'Now Playing',
              initialSize: const Size(400, 225),
              content: Container(
                color: Colors.black,
                child: Center(
                  child: Icon(
                    Icons.play_circle_fill,
                    size: 64,
                    color: Colors.white.withValues(alpha: 0.8),
                  ),
                ),
              ),
              config: const DraggableWindowConfig(
                windowBackgroundColor: Colors.black,
                headerBackgroundColor: Colors.black,
                headerIconColor: Colors.white,
                headerTextStyle: TextStyle(color: Colors.white),
                borderColor: Colors.grey,
                dividerColor: Colors.grey,
              ),
            );
          },
        ),

        // Calculadora - única, com tamanho responsivo
        ElevatedButton.icon(
          icon: const Icon(Icons.code),
          label: const Text('Calc (Único)'),
          onPressed: () {
            windows.open(
              id: 'calculator',
              title: 'Meia Tela',
              initialPosition: const Offset(10, 300),
              content: const Center(child: Text('50% da largura da tela')),
              config: DraggableWindowConfig(
                widthCalculator: (screenWidth) => screenWidth * 0.5,
                heightCalculator: (screenHeight) => 200,
              ),
            );
          },
        ),

        const SizedBox(width: double.infinity, height: 20),

        // Botão para fechar todas
        OutlinedButton.icon(
          icon: const Icon(Icons.close_fullscreen),
          label: const Text('Fechar Todas'),
          style: OutlinedButton.styleFrom(
            foregroundColor: Colors.red,
          ),
          onPressed: () {
            windows.closeAll();
          },
        ),
      ],
    );
  }
}

class UserProfileContent extends StatelessWidget {
  const UserProfileContent({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(16),
      children: [
        const CircleAvatar(
          radius: 40,
          child: Icon(Icons.person, size: 40),
        ),
        const SizedBox(height: 16),
        TextField(
          decoration: const InputDecoration(
            labelText: 'Nome',
            border: OutlineInputBorder(),
            filled: true,
            fillColor: Colors.white,
          ),
          controller: TextEditingController(text: 'Usuário Exemplo'),
        ),
        const SizedBox(height: 12),
        TextField(
          decoration: const InputDecoration(
            labelText: 'Email',
            border: OutlineInputBorder(),
            filled: true,
            fillColor: Colors.white,
          ),
          controller: TextEditingController(text: '[email protected]'),
        ),
        const SizedBox(height: 16),
        SwitchListTile(
          title: const Text('Notificações'),
          value: true,
          onChanged: (val) {},
        ),
        SwitchListTile(
          title: const Text('Modo Escuro'),
          value: false,
          onChanged: (val) {},
        ),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () {},
          child: const Text('Salvar'),
        ),
        const SizedBox(height: 200),
        const Center(child: Text("Final da lista")),
      ],
    );
  }
}
1
likes
160
points
107
downloads

Publisher

unverified uploader

Weekly Downloads

A highly customizable draggable and resizable overlay window widget for Flutter. Perfect for creating floating panels, tool windows, and multi-window interfaces.

Repository (GitHub)
View/report issues

Topics

#widget #window #overlay #draggable #ui

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on draggable_overlay_window