Simple Popup Confirmation Dialog with Flutter

simple_confirm

简洁的确认探出窗

开始使用

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add simple_confirm

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  simple_confirm: ^0.0.1

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:simple_confirm/simple_confirm.dart'; 

example/lib/main.dart

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

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          // Column is also a layout widget. It takes a list of children and
          // arranges them vertically. By default, it sizes itself to fit its
          // children horizontally, and tries to be as tall as its parent.
          //
          // Invoke "debug painting" (press "p" in the console, choose the
          // "Toggle Debug Paint" action from the Flutter Inspector in Android
          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
          // to see the wireframe for each widget.
          //
          // Column has various properties to control how it sizes itself and
          // how it positions its children. Here we use mainAxisAlignment to
          // center the children vertically; the main axis here is the vertical
          // axis because Columns are vertical (the cross axis would be
          // horizontal).
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          final SimpleConfirmOptions options = SimpleConfirmOptions(
              content: "提醒内容提醒内容提醒内容提醒内容提醒内容提醒内容提醒内容提醒内容提醒内容",
              title: "标题",
              confirmText: "确定",
              cancelText: "取消",
              onCancel: () {},
              onConfirm: () {});

          SimpleConfirm.show(context, options: options);
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
} 

Download Details:

Author: 

Source Code: https://pub.dev/packages/simple_confirm

#flutter #dialog #popup 

Simple Popup Confirmation Dialog with Flutter
Rupert  Beatty

Rupert Beatty

1673923860

FFPopup: Presenting Custom Views As A Popup in iOS

FFPopup

FFPopup is a lightweight library for presenting custom views as a popup.

Features

Support several popup show types

  •  None
  •  Fade In
  •  Grow In
  •  Shrink In
  •  Slide In from top, bottom, left, right
  •  Bounce In from top, bottom, left, right, center
  •  Support custom

Support several popup dismiss types

  •  None
  •  Fade Out
  •  Grow Out
  •  Shrink Out
  •  Slide Out to top, bottom, left, right
  •  Bounce Out to top, bottom, left, right, center
  •  Support custom

Layout the popup in the horizontal direction

  •  Left
  •  Right
  •  Center
  •  Left of center
  •  Right of center
  •  Support custom

Layout the popup in the vertical direction

  •  Top
  •  Bottom
  •  Center
  •  Above center
  •  Below center
  •  Support custom

Controlled whether to allow interaction with the underlying view

  •  Allow interaction with underlying view
  •  Don't allow interaction with underlying view
  •  Don't allow interaction with underlying view, dim background
  •  Don't allow interaction with underlying view, blur background
  •  Support custom

Others

  •  Complete Documentation

Requirements

  • iOS 8.0+ / macOS 10.13.6+
  • Xcode 10.1 (10B61) +
Bounce from Top & Bounce to BottomBounce from Top & Bounce to TopBounce in & Bounce outGrow in & Shrink outBounce from Bottom & Slide to BottomSlide from Bottom & Slide to Bottom
001_bounce_from_top&Bounce_to_bottom.gif002_bounce_from_top&bounce_to_top.gif003_bounce_in&bounce_out.gif004_grow_in&shrink_out.gif005_bounce_from_bottom&slide_to_bottom.gif006_slide_from_bottom&slide_to_bottom.gif

Example

To run the FFPopup project, clone the Repo, and start FFPopup in Xcode.

$ git clone https://github.com/JonyFang/FFPopup.git
$ cd FFPopup
$ cd Shell && sh install-bundle.sh && sh install-pods.sh && cd ..
$ open FFPopup.xcworkspace

Installation

There are three ways to use FFPopup in your project:

  • Installation with CocoaPods
  • Installation with Carthage
  • Manually install

CocoaPods

CocoaPods is a dependency manager, which automates and simplifies the process of using 3rd-party libraries like FFPopup in your projects. First, add the following line to your Podfile:

pod 'FFPopup'

If you want to use the latest features of FFPopup use normal external source dependencies.

pod 'FFPopup', :git => 'https://github.com/JonyFang/FFPopup.git'

This pulls from the master branch directly.

Second, install FFPopup into your project:

$ pod install

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate FFPopup into your Xcode project using Carthage, specify it in your Cartfile:

github "JonyFang/FFPopup"

Run the following command to build the framework:

$ carthage update

Drag the built FFPopup.framework binaries from Carthage/Build/iOS into your application’s Xcode project.

On your application targets’ Build Phases settings tab, click the + icon and choose New Run Script Phase. Create a Run Script in which you specify your shell (ex: /bin/sh), add the following contents to the script area below the shell:

/usr/local/bin/carthage copy-frameworks

Add the following paths to the frameworks you want to use under Input Files.

$(SRCROOT)/Carthage/Build/iOS/FFPopup.framework

For an in depth guide, read on from Adding frameworks to an application

Manually

Alternatively you can directly add the FFPopup.h and FFPopup.m source files to your project.

  • Download the latest code version or add the repository as a git submodule to your git-tracked project.
  • Open your project in Xcode, then drag and drop FFPopup.h and FFPopup.m onto your project (use the "Product Navigator view"). Make sure to select Copy items when asked if you extracted the code archive outside of your project.
  • Include FFPopup wherever you need it with #import "FFPopup.h".

Swift

Even though FFPopup is written in Objective-C, it can be used in Swift with no hassle. If you use CocoaPods add the following line to your Podfile:

use_frameworks!

If you added FFPopup manually, just add a bridging header file to your project with the FFPopup header included.

Usage

Import the library where you want to use it.

  • Objective-C
#import <FFPopup.h>

- (void)showPopup {
    FFPopup *popup = [FFPopup popupWithContentView:self.contentView showType:FFPopupShowType_BounceIn dismissType:FFPopupDismissType_ShrinkOut maskType:FFPopupMaskType_Dimmed dismissOnBackgroundTouch:YES dismissOnContentTouch:NO];
    FFPopupLayout layout = FFPopupLayoutMake(FFPopupHorizontalLayout_Center, FFPopupVerticalLayout_Center);
    [popup showWithLayout:layout];
}
  • Swift
import FFPopup

func showPopup() {
    let popup = FFPopup(contentView: self.contentView, showType: .bounceIn, dismissType: .shrinkOut, maskType: .dimmed, dismissOnBackgroundTouch: true, dismissOnContentTouch: false)
    let layout = FFPopupLayout(horizontal: .center, vertical: .center)
    popup.show(layout: layout)
}

Customization

1.FFPopupShowType

Animation transition for presenting contentView. Controlled how the popup will be presented.

The default value is FFPopupShowType_BounceInFromTop.

FFPopupShowType
FFPopupShowType_None
FFPopupShowType_FadeIn
FFPopupShowType_GrowIn
FFPopupShowType_ShrinkIn
FFPopupShowType_SlideInFromTop
FFPopupShowType_SlideInFromBottom
FFPopupShowType_SlideInFromLeft
FFPopupShowType_SlideInFromRight
FFPopupShowType_BounceIn
FFPopupShowType_BounceInFromTop
FFPopupShowType_BounceInFromBottom
FFPopupShowType_BounceInFromLeft
FFPopupShowType_BounceInFromRight

2.FFPopupDismissType

Animation transition for dismissing contentView. Controlled how the popup will be dismissed.

The default value is FFPopupDismissType_BounceOutToBottom.

FFPopupDismissType
FFPopupDismissType_None
FFPopupDismissType_FadeOut
FFPopupDismissType_GrowOut
FFPopupDismissType_ShrinkOut
FFPopupDismissType_SlideOutToTop
FFPopupDismissType_SlideOutToBottom
FFPopupDismissType_SlideOutToLeft
FFPopupDismissType_SlideOutToRight
FFPopupDismissType_BounceOut
FFPopupDismissType_BounceOutToTop
FFPopupDismissType_BounceOutToBottom
FFPopupDismissType_BounceOutToLeft
FFPopupDismissType_BounceOutToRight

3.FFPopupMaskType

Mask prevents background touches from passing to underlying views. Controlled whether to allow interaction with the underlying view.

The default value is FFPopupMaskType_Dimmed.

FFPopupMaskType
FFPopupMaskType_None
FFPopupMaskType_Clear
FFPopupMaskType_Dimmed

4.Other Properties

Property NameDescriptionDefault Value
dimmedMaskAlphaOverrides alpha value for dimmed mask.0.5
showInDurationOverrides animation duration for show in.0.15
dismissOutDurationOverrides animation duration for dismiss out.0.15
shouldDismissOnBackgroundTouchIf YES, the popup will dismiss when background is touched.YES
shouldDismissOnContentTouchIf YES, the popup will dismiss when content view is touched.NO

5.Blocks

/**
 A block to be executed when showing animation started.
 The default value is nil.
 */
@property (nonatomic, copy, nullable) void(^willStartShowingBlock)(void);

/**
 A block to be executed when showing animation finished.
 The default value is nil.
 */
@property (nonatomic, copy, nullable) void(^didFinishShowingBlock)(void);

/**
 A block to be executed when dismissing animation started.
 The default value is nil.
 */
@property (nonatomic, copy, nullable) void(^willStartDismissingBlock)(void);

/**
 A block to be executed when dismissing animation finished.
 The default value is nil.
 */
@property (nonatomic, copy, nullable) void(^didFinishDismissingBlock)(void);

6.Convenience Initializers

Create a new popup with custom values.

/**
 Convenience Initializers
 Create a new popup with `contentView`.
 */
+ (FFPopup *)popupWithContentView:(UIView *)contentView;

/**
 Convenience Initializers
 Create a new popup with custom values.
 
 @param contentView The view you want to appear in popup.
 @param showType    The default value is `FFPopupShowType_BounceInFromTop`.
 @param dismissType The default value is `FFPopupDismissType_BounceOutToBottom`.
 @param maskType    The default value is `FFPopupMaskType_Dimmed`.
 @param shouldDismissOnBackgroundTouch  The default value is `YES`.
 @param shouldDismissOnContentTouch     The default value is `NO`.
 */
+ (FFPopup *)popupWithContentView:(UIView *)contentView
                         showType:(FFPopupShowType)showType
                      dismissType:(FFPopupDismissType)dismissType
                         maskType:(FFPopupMaskType)maskType
         dismissOnBackgroundTouch:(BOOL)shouldDismissOnBackgroundTouch
            dismissOnContentTouch:(BOOL)shouldDismissOnContentTouch;

7.Showing the Popup

/**
 Show popup with center layout.
 `FFPopupVerticalLayout_Center` & `FFPopupHorizontalLayout_Center`
 Showing animation is determined by `showType`.
 */
- (void)show;

/**
 Show popup with specified layout.
 Showing animation is determined by `showType`.
 */
- (void)showWithLayout:(FFPopupLayout)layout;

/**
 Show and then dismiss popup after `duration`.
 If duration is `0.0` or `less`, it will be considered infinity.
 */
- (void)showWithDuration:(NSTimeInterval)duration;

/**
 Show popup with specified `layout` and then dismissed after `duration`.
 If duration is `0.0` or `less`, it will be considered infinity.
 */
- (void)showWithLayout:(FFPopupLayout)layout duration:(NSTimeInterval)duration;

/**
 Show popup at point in view's coordinate system.
 If view is nil, will use screen base coordinates.
 */
- (void)showAtCenterPoint:(CGPoint)point inView:(UIView *)view;

/**
 Show popup at point in view's coordinate system and then dismissed after duration.
 If view is nil, will use screen base coordinates.
 If duration is `0.0` or `less`, it will be considered infinity.
 */
- (void)showAtCenterPoint:(CGPoint)point inView:(UIView *)view duration:(NSTimeInterval)duration;

8.Dismissing the Popup

/**
 Dismiss popup.
 Use `dismissType` if animated is `YES`.
 */
- (void)dismissAnimated:(BOOL)animated;
 /**
 Dismiss all the popups in the app.
 */
+ (void)dismissAllPopups;

/**
 Dismiss the popup for contentView.
 */
+ (void)dismissPopupForView:(UIView *)view animated:(BOOL)animated;

/**
 Dismiss super popup.
 Iterate over superviews until you find a `FFPopup` and dismiss it.
 */
+ (void)dismissSuperPopupIn:(UIView *)view animated:(BOOL)animated;

TODO List

This is the to-do list for the FFPopup project. You can join us to become a contributor.

  •  Support blur option for background mask
  •  Support for keyboard show/hide
  •  Support for drag-to-dismiss

See the CONTRIBUTING file for contributing guidelines.

Live Demo

My app Time Card -Countdown (Never Forget Important Days) is using FFPopup. You can download it and try it on your multiple devices to experience the effect.

 

Download Details:

Author: JonyFang
Source Code: https://github.com/JonyFang/FFPopup 
License: MIT license

#swift #alert #objective-c #popup 

FFPopup: Presenting Custom Views As A Popup in iOS
Rupert  Beatty

Rupert Beatty

1668134460

Alerttoast: Create Apple-like Alerts & Toasts using SwiftUI

AlertToast-SwiftUI

Present Apple-like alert & toast in SwiftUI

🌄 Example

ToastExample.gif

🔭 Overview

Currently in SwiftUI, the only way to inform the user about some process that finished for example, is by using Alert. Sometimes, you just want to pop a message that tells the user that something completed, or his message was sent. Apple doesn't provide any other method rather than using Alert even though Apple using all kinds of different pop-ups. The results are poor UX where the user would need to tap "OK/Dismiss" for every little information that he should be notified about.

Alert Toast is an open-source library in Github to use with SwiftUI. It allows you to present popups that don't need any user action to dismiss or to validate. Some great usage examples: Message Sent, Poor Network Connection, Profile Updated, Logged In/Out, Favorited, Loading and so on…

  • Built with pure SwiftUI.
  • 3 Display modes: Alert (pop at the center), HUD (drop from the top) and Banner (pop/slide from the bottom).
  • Complete, Error SystemImage, Image, Loading, and Regular (Only Text).
  • Supports Light & Dark Mode.
  • Works with any kind of view builder.
  • Localization support.
  • Font & Background customization.

If you like the project, don't forget to put star 🌟.

💻 Installation

Cocoapods

AlertToast Cocapods Website

CocoaPods is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate AlertToast into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'AlertToast'

Swift Package Manager

The Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

To integrate AlertToast into your Xcode project using Xcode 12, specify it in File > Swift Packages > Add Package Dependency...:

https://github.com/elai950/AlertToast.git, :branch="master"

For Xcode 13, please refer this article to install AlertToast


Manually

If you prefer not to use any of dependency managers, you can integrate AlertToast into your project manually. Put Sources/AlertToast folder in your Xcode project. Make sure to enable Copy items if needed and Create groups.

🧳 Requirements

  • iOS 13.0+ | macOS 11+
  • Xcode 12.0+ | Swift 5+

🛠 Usage

First, add import AlertToast on every swift file you would like to use AlertToast.

Then, use the .toast view modifier:

Parameters:

  • isPresenting: (MUST) assign a Binding<Bool> to show or dismiss alert.
  • duration: default is 2, set 0 to disable auto dismiss.
  • tapToDismiss: default is true, set false to disable.
  • alert: (MUST) expects AlertToast.

Usage example with regular alert

import AlertToast
import SwiftUI

struct ContentView: View{

    @State private var showToast = false

    var body: some View{
        VStack{

            Button("Show Toast"){
                 showToast.toggle()
            }
        }
        .toast(isPresenting: $showToast){

            // `.alert` is the default displayMode
            AlertToast(type: .regular, title: "Message Sent!")
            
            //Choose .hud to toast alert from the top of the screen
            //AlertToast(displayMode: .hud, type: .regular, title: "Message Sent!")
            
            //Choose .banner to slide/pop alert from the bottom of the screen
            //AlertToast(displayMode: .banner(.slide), type: .regular, title: "Message Sent!")
        }
    }
}

Complete Modifier Example

.toast(isPresenting: $showAlert, duration: 2, tapToDismiss: true, alert: {
   //AlertToast goes here
}, onTap: {
   //onTap would call either if `tapToDismis` is true/false
   //If tapToDismiss is true, onTap would call and then dismis the alert
}, completion: {
   //Completion block after dismiss
})

Alert Toast Parameters

AlertToast(displayMode: DisplayMode,
           type: AlertType,
           title: Optional(String),
           subTitle: Optional(String),
           style: Optional(AlertStyle))
           
//This is the available customizations parameters:
AlertStyle(backgroundColor: Color?,
            titleColor: Color?,
            subTitleColor: Color?,
            titleFont: Font?,
            subTitleFont: Font?)

Available Alert Types:

  • Regular: text only (Title and Subtitle).
  • Complete: animated checkmark.
  • Error: animated xmark.
  • System Image: name image from SFSymbols.
  • Image: name image from Assets.
  • Loading: Activity Indicator (Spinner).

Alert dialog view modifier (with default settings):

.toast(isPresenting: Binding<Bool>, duration: Double = 2, tapToDismiss: true, alert: () -> AlertToast , onTap: () -> (), completion: () -> () )

Simple Text Alert:

AlertToast(type: .regular, title: Optional(String), subTitle: Optional(String))

Complete/Error Alert:

AlertToast(type: .complete(Color)/.error(Color), title: Optional(String), subTitle: Optional(String))

System Image Alert:

AlertToast(type: .systemImage(String, Color), title: Optional(String), subTitle: Optional(String))

Image Alert:

AlertToast(type: .image(String), title: Optional(String), subTitle: Optional(String))

Loading Alert:

//When using loading, duration won't auto dismiss and tapToDismiss is set to false
AlertToast(type: .loading, title: Optional(String), subTitle: Optional(String))

You can add many .toast on a single view.

📖 Article

I wrote an article that contains more usage examples.

Medium - How to toast an alert in SwiftUI

👨‍💻 Contributors

All issue reports, feature requests, pull requests and GitHub stars are welcomed and much appreciated.



Download Details:

Author: elai950
Source Code: https://github.com/elai950/AlertToast 
License: MIT license

#swift #apple #alert #xcode #dialog #popup 

Alerttoast: Create Apple-like Alerts & Toasts using SwiftUI

Custom Popup Menu in Flutter

 

 

CustomPopupMenu

Wrap a widget with CustomPopupMenu, Tap or Long Press this widget, a popup menu would display in a suitable position.

Features

  • Gesture: Tap/Long Press
  • Fully customized menu: This package doesn't preset any style of menu, the common styles see: example/lib/main.dart.
  • Auto calculate the position of menu, also supports manual adjustment.

Demo

Using this package, you are free to build similar popup menu in WeChat.

 

   

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add custom_pop_up_menu

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  custom_pop_up_menu: ^1.2.4

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:custom_pop_up_menu/custom_pop_up_menu.dart'; 

example/lib/main.dart

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

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

class ChatModel {
  String content;
  bool isMe;

  ChatModel(this.content, {this.isMe = false});
}

class ItemModel {
  String title;
  IconData icon;

  ItemModel(this.title, this.icon);
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CustomPopupMenu',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late List<ChatModel> messages;
  late List<ItemModel> menuItems;
  CustomPopupMenuController _controller = CustomPopupMenuController();

  @override
  void initState() {
    messages = [
      ChatModel('在吗?'),
      ChatModel('咋了?找我有事吗?', isMe: true),
      ChatModel('没啥就像看看你在不在'),
      ChatModel('到底啥事你说啊,我还在工作呢', isMe: true),
      ChatModel('?', isMe: true),
      ChatModel('下面开始介绍Flutter'),
      ChatModel(
          'Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。'),
      ChatModel('就这???', isMe: true),
      ChatModel('在吗?'),
      ChatModel('咋了?找我有事吗?', isMe: true),
      ChatModel('没啥就像看看你在不在'),
      ChatModel('到底啥事你说啊,我还在工作呢', isMe: true),
      ChatModel('?', isMe: true),
      ChatModel('下面开始介绍Flutter'),
      ChatModel(
          'Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面。 Flutter可以与现有的代码一起工作。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。'),
      ChatModel('就这???', isMe: true),
    ];
    menuItems = [
      ItemModel('发起群聊', Icons.chat_bubble),
      ItemModel('添加朋友', Icons.group_add),
      ItemModel('扫一扫', Icons.settings_overscan),
    ];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('CustomPopupMenu'),
        actions: <Widget>[
          CustomPopupMenu(
            child: Container(
              child: Icon(Icons.add_circle_outline, color: Colors.white),
              padding: EdgeInsets.all(20),
            ),
            menuBuilder: () => ClipRRect(
              borderRadius: BorderRadius.circular(5),
              child: Container(
                color: const Color(0xFF4C4C4C),
                child: IntrinsicWidth(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: menuItems
                        .map(
                          (item) => GestureDetector(
                            behavior: HitTestBehavior.translucent,
                            onTap: () {
                              print("onTap");
                              _controller.hideMenu();
                            },
                            child: Container(
                              height: 40,
                              padding: EdgeInsets.symmetric(horizontal: 20),
                              child: Row(
                                children: <Widget>[
                                  Icon(
                                    item.icon,
                                    size: 15,
                                    color: Colors.white,
                                  ),
                                  Expanded(
                                    child: Container(
                                      margin: EdgeInsets.only(left: 10),
                                      padding:
                                          EdgeInsets.symmetric(vertical: 10),
                                      child: Text(
                                        item.title,
                                        style: TextStyle(
                                          color: Colors.white,
                                          fontSize: 12,
                                        ),
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ),
                        )
                        .toList(),
                  ),
                ),
              ),
            ),
            pressType: PressType.singleClick,
            verticalMargin: -10,
            controller: _controller,
          ),
        ],
      ),
      body: LayoutBuilder(
        builder: (context, constraint) {
          return SingleChildScrollView(
            physics: AlwaysScrollableScrollPhysics(),
            child: ConstrainedBox(
              constraints: BoxConstraints(minHeight: constraint.maxHeight),
              child: Column(
                children: messages
                    .map(
                      (message) => MessageContent(
                        message,
                      ),
                    )
                    .toList(),
              ),
            ),
          );
        },
      ),
    );
  }
}

// ignore: must_be_immutable
class MessageContent extends StatelessWidget {
  MessageContent(this.message);

  final ChatModel message;
  List<ItemModel> menuItems = [
    ItemModel('复制', Icons.content_copy),
    ItemModel('转发', Icons.send),
    ItemModel('收藏', Icons.collections),
    ItemModel('删除', Icons.delete),
    ItemModel('多选', Icons.playlist_add_check),
    ItemModel('引用', Icons.format_quote),
    ItemModel('提醒', Icons.add_alert),
    ItemModel('搜一搜', Icons.search),
  ];

  Widget _buildLongPressMenu() {
    return ClipRRect(
      borderRadius: BorderRadius.circular(5),
      child: Container(
        width: 220,
        color: const Color(0xFF4C4C4C),
        child: GridView.count(
          padding: EdgeInsets.symmetric(horizontal: 5, vertical: 10),
          crossAxisCount: 5,
          crossAxisSpacing: 0,
          mainAxisSpacing: 10,
          shrinkWrap: true,
          physics: NeverScrollableScrollPhysics(),
          children: menuItems
              .map((item) => Column(
                    mainAxisSize: MainAxisSize.min,
                    children: <Widget>[
                      Icon(
                        item.icon,
                        size: 20,
                        color: Colors.white,
                      ),
                      Container(
                        margin: EdgeInsets.only(top: 2),
                        child: Text(
                          item.title,
                          style: TextStyle(color: Colors.white, fontSize: 12),
                        ),
                      ),
                    ],
                  ))
              .toList(),
        ),
      ),
    );
  }

  Widget _buildAvatar(bool isMe, double size) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(5),
      child: Container(
        color: isMe ? Colors.blueAccent : Colors.pinkAccent,
        width: size,
        height: size,
        child: Icon(
          isMe ? Icons.face : Icons.tag_faces,
          color: Colors.white,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    bool isMe = message.isMe;
    double avatarSize = 40;

    return Container(
      margin: EdgeInsets.all(10),
      child: Row(
        textDirection: isMe ? TextDirection.rtl : TextDirection.ltr,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Container(
            margin: EdgeInsets.only(right: isMe ? 0 : 10, left: isMe ? 10 : 0),
            child: CustomPopupMenu(
              child: _buildAvatar(isMe, avatarSize),
              menuBuilder: () => GestureDetector(
                child: _buildAvatar(isMe, 100),
                onLongPress: () {
                  print("onLongPress");
                },
                onTap: () {
                  print("onTap");
                },
              ),
              barrierColor: Colors.transparent,
              pressType: PressType.singleClick,
              arrowColor: isMe ? Colors.blueAccent : Colors.pinkAccent,
              position: PreferredPosition.top,
            ),
          ),
          CustomPopupMenu(
            child: Container(
              padding: EdgeInsets.all(10),
              constraints: BoxConstraints(maxWidth: 240, minHeight: avatarSize),
              decoration: BoxDecoration(
                color: isMe ? Color(0xff98e165) : Colors.white,
                borderRadius: BorderRadius.circular(3.0),
              ),
              child: Text(message.content),
            ),
            menuBuilder: _buildLongPressMenu,
            barrierColor: Colors.transparent,
            pressType: PressType.longPress,
          )
        ],
      ),
    );
  }
} 

Download Details:

Author: malikwang

Source Code: https://github.com/malikwang/custom_pop_up_menu

#flutter #popup #custom 

Custom Popup Menu in Flutter
Rupert  Beatty

Rupert Beatty

1665957900

SwiftEntryKit: A Presentation Library for iOS

SwiftEntryKit

🤗 Donations can be made here.

Overview

SwiftEntryKit is a simple yet versatile content presenter written in Swift.

Features

Banners or pop-ups are called Entries.

  • Entries are displayed inside a separate UIWindow (of type EKWindow), so users are able to navigate the app freely while entries are being displayed in a non intrusive manner.
  • The kit offers beautiful presets that can be themed with your own colors and fonts.
  • Customization: Entries are highly customizable
    •  Can be positioned either at the top, center, or the bottom of the screen.
    •  Can be displayed within or outside the screen safe area.
    •  Can be stylized: have a border, drop-shadow and round corners.
    •  Their content and the surrounding background can be blurred, dimmed, colored or have a gradient style.
    •  Transition animations are customizable - entrance, exit and pop (by another entry).
    •  The user interaction with the entry or the screen can be intercepted.
    •  Entries can be enqueued or override previous entries using the precedence attribute.
    •  Each entry has a display priority attribute. That means that it can be dismissed only by other entry with an equal or higher priority.
    •  Presets support accessibility.
    •  Entries have an optional rubber banding effect while panning.
    •  Entries can be optionally dismissed using a simple swipe gesture.
    •  Entries can be optionally injected with lifecycle events: will and did appear/disappear.
    •  The status bar style is settable for the display duration of the entry.
    •  Supports navigation controllers & custom views as well!

Example Project

The example project contains various presets and examples you can use and modify as your like.

Example Project Installation

You can either use the terminal or git client such as Source Tree.

Terminal Users

$ git clone https://github.com/huri000/SwiftEntryKit.git

Git Client (Source Tree)

Clone https://github.com/huri000/SwiftEntryKit.git

Presets

ToastsNotesFloatsPopups
toasts_examplenotes_examplefloats_examplepopup_example
AlertsFormsRatingMore...
alert_exampleform_examplerating_examplecustom_example

Playground

noun: a place where people can play 🏈

The example app contains a playground screen, an interface that allows you to customize your preferable entries. The playground screen has some limitations (allows to select constant values) but you can easily modify the code to suit your needs. Check it out!

The Playground ScreenTop Toast Sample
playground_exampleplayground-sample-1

Requirements

  • iOS 9 or any higher version.
  • Xcode 9 or any higher version.
  • Swift 4.0 or any higher version.
  • The library has not been tested with iOS 8.x.y or a lower version.

Installation

  • SwiftEntryKit is compatible with Swift 5 as of release 1.0.0.
  • SwiftEntryKit is compatible with Swift 4.2 as of release 0.8.1.
  • Developers who use lower Swift version should install release 0.7.2.

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

To integrate SwiftEntryKit into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/cocoapods/specs.git'
platform :ios, '9.0'
use_frameworks!

pod 'SwiftEntryKit', '2.0.0'

Then, run the following command:

$ pod install

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate SwiftEntryKit into your Xcode project using Carthage, specify the following in your Cartfile:

github "huri000/SwiftEntryKit" == 2.0.0

Accio

Accio is a decentralized dependency manager driven by SwiftPM that works for iOS/tvOS/watchOS/macOS projects.

You can install Accio with Homebrew using the following command:

$ brew tap JamitLabs/Accio https://github.com/JamitLabs/Accio.git
$ brew install accio

To integrate SwiftEntryKit into your Xcode project using Accio, specify the following in your Package.swift manifest:

.package(url: "https://github.com/huri000/SwiftEntryKit", .exact("2.0.0"))

After specifying "SwiftEntryKit" as a dependency of the target in which you want to use it, run accio install.

Usage

Quick Usage

No setup is needed! Each time you wish to display an entry, just create your view and initialize an EKAttributes struct. See also the preset usage example, and the example project. likewise:

// Customized view
let customView = SomeCustomView()
/*
Do some customization on customView
*/

// Attributes struct that describes the display, style, user interaction and animations of customView.
var attributes = EKAttributes()
/*
Adjust preferable attributes
*/

And then, just call:

SwiftEntryKit.display(entry: customView, using: attributes)

The kit will replace the application main window with the EKWindow instance and display the entry.

Entry Attributes

EKAttributes is the entry's descriptor. Each time an entry is displayed, an EKAttributes struct is necessary to describe the entry's presentation, position inside the screen, the display duration, its frame constraints (if needed), its styling (corners, border and shadow), the user interaction events, the animations (in / out) and more.

Create a mutable EKAttributes structure likewise:

var attributes = EKAttributes()

Below are the properties that can be modified in the EKAttributes:

Entry Name

Entries can have names. When an EKAttributes struct is instantiated, it is nameless, meaning, the name property is nil. It is recommended to set a meaningful name for an entry.

attributes.name = "Top Note"

Entries with names can be specifically referred to later, for example, you can inquire whether a specific entry is currently displayed:

if SwiftEntryKit.isCurrentlyDisplaying(entryNamed: "Top Note") {
    /* Do your things */
}

Window Level

Entries can be displayed above the application main window, above the status bar, above the alerts window or even have a custom level (UIWindowLevel).

For example, set the window level to normal, likewise:

attributes.windowLevel = .normal

This causes the entry to appear above the application key window and below the status bar.

The default value of windowLevel is .statusBar.

Display Position

The entry can be displayed either at the top, center, or the bottom of the screen.

For example, set the display position to bottom, likewise:

attributes.position = .bottom

The default value of position is .top.

Precedence

The precedence attribute of an entry describes the manner in which entries are pushed in. It offers 2 approaches for managing the presentation priority of multiple simultaneous entries.

Override

If the display priority is equal or higher than the currently displayed entry, override it.

Example for setting .override precedence with .max display priority while ignoring entries that are already enqueued (leaving them to display after the new entry is dismissed).

attributes.precedence = .override(priority: .max, dropEnqueuedEntries: false)

You can optionally flush the entries that are inside the queue.

In case dropEnqueuedEntries is false, enqueued entries remain in the queue. The first enqueued entry will show right after the new entry pops out. In case dropEnqueuedEntries is true, the entry-queue is flushed as the new entry is being displayed.

Enqueue

If the queue is empty, display the entry immediately, otherwise, insert the entry into the queue until its turn to show arrives.

Example for setting .enqueue precedence with .normal display priority:

attributes.precedence = .enqueue(priority: .normal)

Heuristics

There are 2 possible heuristics for entries prioritization in the queue:

  • Display Priority Queue: The entries are sorted by their display priority, then by chronological order.
  • Chronological Queue: The entries are sorted only by their chronological order (standard queue).

Select the heuristic that suits you best by doing the following, only once, before using SwiftEntryKit to display entries.

EKAttributes.Precedence.QueueingHeuristic.value = .priority

Or:

EKAttributes.Precedence.QueueingHeuristic.value = .chronological

The default value of EKAttributes.Precedence.QueueingHeuristic.value is .priority.

The default value of precedence is .override(priority: .normal, dropEnqueuedEntries: false).

Display Priority

The display priority of the entry determines whether it dismisses other entries or is dismissed by them. An entry can be dismissed only by an entry with an equal or a higher display priority.

let highPriorityAttributes = EKAttributes()
highPriorityAttributes.precedence.priority = .high

let normalPriorityAttributes = EKAttributes()
normalPriorityAttributes.precedence.priority = .normal

// Display high priority entry
SwiftEntryKit.display(entry: view1, using: highPriorityAttributes)

// Display normal priority entry (ignored!)
SwiftEntryKit.display(entry: view2, using: normalPriorityAttributes)

view2 won't be displayed!

Display Duration

The display duration of the entry (Counted from the moment the entry has finished its entrance animation and until the exit animation begins).

Display for 4 seconds:

attributes.displayDuration = 4

Display for an infinite duration

attributes.displayDuration = .infinity

The default value of displayDuration is 2.

Position Constraints

Constraints that tie the entry tightly to the screen context, for example: Height, Width, Max Width, Max Height, Additional Vertical Offset & Safe Area related info.

  • Entries that support Auto Layout - Their height is inferred from the constraints that applied to them.
  • Entries that don't support Auto Layout - Their exact size must be explicitly set using positionConstraints's size property.

For example:

Ratio edge - signifies that the ratio of the width edge has a ratio of 0.9 of the screen's width.

let widthConstraint = EKAttributes.PositionConstraints.Edge.ratio(value: 0.9)

Intrinsic edge - signifies that the wanted height value is the content height - Decided by the entries vertical constraints

let heightConstraint = EKAttributes.PositionConstraints.Edge.intrinsic

Create the entry size constraints likewise:

attributes.positionConstraints.size = .init(width: widthConstraint, height: heightConstraint)

You can also set attributes.positionConstraints.maxSize in order to make sure the entry does not exceeds predefined limitations. This is useful on device orientation change.

Safe Area - can be used to override the safe area or to color it (More examples are in the example project) That snippet implies that the safe area insets should be kept and not be a part of the entry.

attributes.positionConstraints.safeArea = .empty(fillSafeArea: false)

Vertical Offset - an additional offset that can be applied to the entry (Other than the safe area).

attributes.positionConstraints.verticalOffset = 10

Autorotation - whether the entry autorotates along with the orientation of the device. Defaults to true.

attributes.positionConstraints.rotation.isEnabled = false

Keyboard Releation - used to bind an entry to the keyboard once the keyboard is displayed.

let offset = EKAttributes.PositionConstraints.KeyboardRelation.Offset(bottom: 10, screenEdgeResistance: 20)
let keyboardRelation = EKAttributes.PositionConstraints.KeyboardRelation.bind(offset: offset)
attributes.positionConstraints.keyboardRelation = keyboardRelation

In the example above the entry's bottom is tuned to have a 10pts offset from the top of the keyboard (while it shows) Because the entry's frame might exceed the screen bounds, the user might not see all the entry - we wouldn't want that. Therefore, an additional associated value has been added - screenEdgeResistance with value of 20pts. That is, to make sure that the entry remains within the bounds of the screen, and always visible to the user. The extreme situation might occur as the device orientation is landscape and the keyboard shows up (See example project form presets for more information).

User Interaction

The entry and the screen can be interacted by the user. User interaction be can intercepted in various ways:

An interaction (Any touch whatsoever) with the entry delays its exit by 3s:

attributes.entryInteraction = .delayExit(by: 3)

A tap on the entry / screen dismisses it immediately:

attributes.entryInteraction = .dismiss
attributes.screenInteraction = .dismiss

A tap on the entry is swallowed (ignored):

attributes.entryInteraction = .absorbTouches

A tap on the screen is forwarded to the lower level window, in most cases the receiver will be the application window. This is very useful when you want to display an unintrusive content like banners and push notification entries.

attributes.screenInteraction = .forward

Pass additional actions that are invoked when the user taps the entry:

let action = {
    // Do something useful
}
attributes.entryInteraction.customTapActions.append(action)

The default value of screenInteraction is .forward.

The default value of entryInteraction is .dismiss.

Scroll Behavior

Describes the entry behavior when it's being scrolled, that is, dismissal by a swipe gesture and a rubber band effect much similar to a UIScrollView.

Disable the pan and swipe gestures on the entry:

attributes.scroll = .disabled

Enable swipe and stretch and pullback with jolt effect:

attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)

Enable swipe and stretch and pullback with an ease-out effect:

attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .easeOut)

Enable swipe but disable stretch:

attributes.scroll = .edgeCrossingDisabled(swipeable: true)

The default value of scroll is .enabled(swipeable: true, pullbackAnimation: .jolt).

Haptic Feedback

The device can produce a haptic feedback, thus adding an additional sensory depth to each entry.

The default value of hapticFeedbackType is .none.

Lifecycle Events

Events can be injected to the entry so that they are to be called during its lifecycle.

attributes.lifecycleEvents.willAppear = {
    // Executed before the entry animates inside 
}

attributes.lifecycleEvents.didAppear = {
    // Executed after the entry animates inside
}

attributes.lifecycleEvents.willDisappear = {
    // Executed before the entry animates outside
}

attributes.lifecycleEvents.didDisappear = {
    // Executed after the entry animates outside
}

Display Mode

To allow you to fully support any user interface style, SwiftEntryKit introduces two specialized types:

  • EKColor describes a color under light and dark modes.
  • EKAttributes.BackgroundStyle.BlurStyle describes a blur effect under light and dark modes.

The following forces SwiftEntryKit to display the entry on dark mode.

attributes.displayMode = .dark

The possible values are: .light, .dark, .inferred. The default value is .inferred, which means that the entry will be displayed with the current user interface style.

Background Style

The entry and the screen can have various background styles, such as blur, color, gradient and even an image.

The following example implies clear background for both the entry and the screen:

attributes.entryBackground = .clear
attributes.screenBackground = .clear

Colored entry background and dimmed screen background:

attributes.entryBackground = .color(color: .standardContent)
attributes.screenBackground = .color(color: EKColor(UIColor(white: 0.5, alpha: 0.5)))

Gradient entry background (diagonal vector):

let colors: [EKColor] = ...
attributes.entryBackground = .gradient(gradient: .init(colors: colors, startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))

Visual Effect entry background:

attributes.entryBackground = .visualEffect(style: .dark)

The default value of entryBackground and screenBackground is .clear.

Shadow

The shadow that surrounds the entry.

Enable shadow around the entry:

attributes.shadow = .active(with: .init(color: .black, opacity: 0.3, radius: 10, offset: .zero))

Disable shadow around the entry:

attributes.shadow = .none

The default value of shadow is .none.

Round Corners

Round corners around the entry.

Only top left and right corners with radius of 10:

attributes.roundCorners = .top(radius: 10)

Only bottom left and right corners with radius of 10:

attributes.roundCorners = .bottom(radius: 10)

All corners with radius of 10:

attributes.roundCorners = .all(radius: 10)

No round corners:

attributes.roundCorners = .none

The default value of roundCorners is .none.

Border

The border around the entry.

Add a black border with thickness of 0.5pts:

attributes.border = .value(color: .black, width: 0.5)

No border:

attributes.border = .none

The default value of border is .none.

Animations

Describes how the entry animates into and out of the screen.

  • Each animation descriptor can have up to 3 types of animations at the same time. Those can be combined to a single complex one!
  • Translation animation anchor can be explicitly set but it receives a default value according to position of the entry.

Example for translation from top with spring, scale in and even fade in as a single entrance animation:

attributes.entranceAnimation = .init(
                 translate: .init(duration: 0.7, anchorPosition: .top, spring: .init(damping: 1, initialVelocity: 0)), 
                 scale: .init(from: 0.6, to: 1, duration: 0.7), 
                 fade: .init(from: 0.8, to: 1, duration: 0.3))

The default value of entranceAnimation and exitAnimation is .translation - The entry translates in or out, respectively, with duration of 0.3 seconds.

Pop Behavior

Describes the entry behavior when it's being popped (dismissed by an entry with equal / higher display-priority.

The entry is being popped animatedly:

attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.2)))

The entry is being overridden (Disappears promptly):

attributes.popBehavior = .overridden

The default value of popBehavior is .animated(animation: .translation) - It translates out with duration of 0.3 seconds.

Status Bar

The status bar appearance can be modified during the display of the entry. SwiftEntryKit supports both View controller-based status bar appearance and manual setting.

Setting the status bar style is fairly simple -

Status bar becomes visible and gets a light style:

attributes.statusBar = .light

The status bar becomes hidden:

attributes.statusBar = .hidden

The status bar appearance is inferred from the previous context (won't be changed):

attributes.statusBar = .inferred

In case there is an already presenting entry with lower/equal display priority, the status bar will change its style. When the entry is removed, the status bar gets its initial style back.

The default value of statusBar is .inferred.

EKAttributes' interface is as follows:

public struct EKAttributes

    // Identification
    public var name: String?

    // Display
    public var windowLevel: WindowLevel
    public var position: Position
    public var precedence: Precedence
    public var displayDuration: DisplayDuration
    public var positionConstraints: PositionConstraints

    // User Interaction
    public var screenInteraction: UserInteraction
    public var entryInteraction: UserInteraction
    public var scroll: Scroll
    public var hapticFeedbackType: NotificationHapticFeedback
    public var lifecycleEvents: LifecycleEvents

    // Theme & Style
    public var displayMode = DisplayMode.inferred
    public var entryBackground: BackgroundStyle
    public var screenBackground: BackgroundStyle
    public var shadow: Shadow
    public var roundCorners: RoundCorners
    public var border: Border
    public var statusBar: StatusBar
    
    // Animations
    public var entranceAnimation: Animation
    public var exitAnimation: Animation
    public var popBehavior: PopBehavior
}

Presets Usage Example:

You can use one of the presets that come with SwiftEntryKit, doing these 4 simple steps:

  1. Create your EKAttributes struct and set your preferable properties.
  2. Create EKNotificationMessage struct (The Content) and set the content.
  3. Create EKNotificationMessageView (The View) and inject EKNotificationMessage struct to it.
  4. Display the entry using SwiftEntryKit class method.

EKNotificationMessageView preset example:

// Generate top floating entry and set some properties
var attributes = EKAttributes.topFloat
attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(.red), EKColor(.green)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
attributes.statusBar = .dark
attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.minEdge), height: .intrinsic)

let title = EKProperty.LabelContent(text: titleText, style: .init(font: titleFont, color: textColor))
let description = EKProperty.LabelContent(text: descText, style: .init(font: descFont, color: textColor))
let image = EKProperty.ImageContent(image: UIImage(named: imageName)!, size: CGSize(width: 35, height: 35))
let simpleMessage = EKSimpleMessage(image: image, title: title, description: description)
let notificationMessage = EKNotificationMessage(simpleMessage: simpleMessage)

let contentView = EKNotificationMessageView(with: notificationMessage)
SwiftEntryKit.display(entry: contentView, using: attributes)

Custom View Usage Example:

// Create a basic toast that appears at the top
var attributes = EKAttributes.topToast

// Set its background to white
attributes.entryBackground = .color(color: .white)

// Animate in and out using default translation
attributes.entranceAnimation = .translation
attributes.exitAnimation = .translation

let customView = UIView()
/*
... Customize the view as you like ...
*/

// Display the view with the configuration
SwiftEntryKit.display(entry: customView, using: attributes)

Displaying a View Controller

As from version 0.4.0, view controllers are supported as well.

SwiftEntryKit.display(entry: customViewController, using: attributes)

Alternative Rollback Window

By default, the window held by the application delegate becomes the key again right after SwiftEntryKit has finished displaying the entry. This behavior can be changed using rollbackWindow parameter.

SwiftEntryKit.display(entry: view, using: attributes, rollbackWindow: .custom(window: alternativeWindow))

After the entry has been dismissed, the given window alternativeWindow would become the key instead of the window that is held by the application delegate.

Dismissing an Entry

You can dismiss the currently displayed entry by simply invoke dismiss in the SwiftEntryKit class, likewise:

SwiftEntryKit.dismiss()

Or:

SwiftEntryKit.dismiss(.displayed)

This dismisses the entry animatedly using its exitAnimation attribute and on completion, the window would be removed as well.

You can dismiss the currently displayed entry and flush the queue as well, likewise:

SwiftEntryKit.dismiss(.all)

Only flush the queue, leaving any currently displayed entry to its natural lifecycle:

SwiftEntryKit.dismiss(.queue)

Dismiss a specific entry by name - either currently displayed or enqueued. All the entries with the given name are dismissed.

SwiftEntryKit.dismiss(.specific(entryName: "Entry Name"))

Dismiss any entry with a lower or equal display priority of .normal.

SwiftEntryKit.dismiss(.prioritizedLowerOrEqualTo(priority: .normal))

Using a completion handler

Inject a trailing closure to be executed after the entry dismissal.

SwiftEntryKit.dismiss {
    // Executed right after the entry has been dismissed
}

Is Currently Displaying

Inquire whether an entry is currently displayed:

if SwiftEntryKit.isCurrentlyDisplaying {
    /* Do your things */
}

Inquire whether a specific entry is currently displayed using the name property inside EKAttributes.

if SwiftEntryKit.isCurrentlyDisplaying(entryNamed: "Top Note") {
/* Do your things */
}

Queue Contains

Inquire whether the queue of entries is not empty:

if SwiftEntryKit.isQueueEmpty {
    /* Do your things */
}

Inquire whether the queue of entries contains an entry with name:

if SwiftEntryKit.queueContains(entryNamed: "Custom-Name") {
    /* Do your things */
}

Swiping and Rubber Banding

Entries can be panned vertically (This ability can be enabled using the scroll attributes). Thefore it's only natural that an entry can be dismissed using a swipe-like gesture.

Enable swipe gesture. When the swipe gesture fails (doesn't pass the velocity threshold) ease it back.

attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .easeOut)

Enable swipe gesture. When the swipe gesture fails throw it back out with a jolt.

attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)

The PullbackAnimation values (duration, damping & initialSpringVelocity) can be customized as well.

SwipeJolt
swipe_exampleband_example

Dealing with safe area:

EKAttributes.PositionConstraints.SafeArea may be used to override the safe area with the entry's content, or to fill the safe area with a background color (like Toasts do), or even leave the safe area empty (Like Floats do).

SwiftEntryKit supports iOS 11.x.y and is backward compatible to iOS 9.x.y, so the status bar area is treated as same as the safe area in earlier iOS versions.

Dealing with orientation change:

SwiftEntryKit identifies orientation changes and adjust the entry's layout to those changes. Therefore, if you wish to limit the entries's width, you are able to do so by giving it a maximum value, likewise:

var attributes = EKAttributes.topFloat

// Give the entry the width of the screen minus 20pts from each side, the height is decided by the content's contraint's
attributes.positionConstraints.size = .init(width: .offset(value: 20), height: .intrinsic)

// Give the entry maximum width of the screen minimum edge - thus the entry won't grow much when the device orientation changes from portrait to landscape mode.
let edgeWidth = min(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
attributes.positionConstraints.maxSize = .init(width: .constant(value: edgeWidth), height: .intrinsic)

let customView = UIView()
/*
... Customize the view as you like ...
*/

// Use class method of SwiftEntryKit to display the view using the desired attributes
SwiftEntryKit.display(entry: customView, using: attributes)
Orientation Change Demonstration
orientation_change

Dark Mode in the Example Project

You can tinker with the display mode using a segmented control on presets screen, forcing light and dark modes. All the presets are dark mode ready, but only some in the example project demonstrate dark mode capabilities.

light_dark

Swift and Objective-C Interoperability

SwiftEntryKit's APIs use the Swift language exclusive syntax (enums, associated values, and more). Therefore, SwiftEntryKit cannot be referenced directly from an Objective-C file (.m, .h or .mm).

Yet, it is pretty easy to integrate SwiftEntryKit into an Objective-C project using a simple .swift class that is a sort of adapter between SwiftEntryKit and your Objective-C code.

This project demonstrates that using Carthage and CocoaPods.

Download Details:

Author: Huri000
Source Code: https://github.com/huri000/SwiftEntryKit 
License: MIT license

#swift #banner #popup #notification 

SwiftEntryKit: A Presentation Library for iOS
Lawrence  Lesch

Lawrence Lesch

1662352020

Tippyjs: Tooltip, Popover, Dropdown, and Menu Library

Tippy.js

The complete tooltip, popover, dropdown, and menu solution for the web 

Installation

Package Managers

# npm
npm i tippy.js

# Yarn
yarn add tippy.js

Import the tippy constructor and the core CSS:

import tippy from 'tippy.js';
import 'tippy.js/dist/tippy.css';

CDN

<script src="https://unpkg.com/@popperjs/core@2"></script>
<script src="https://unpkg.com/tippy.js@6"></script>

The core CSS comes bundled with the default unpkg import.

Demo and Documentation

➡️ View the latest demo & docs here

Migration Guide

Usage

For detailed usage information, visit the docs.

Component Wrappers

Download Details:

Author: Atomiks
Source Code: https://github.com/atomiks/tippyjs 
License: MIT license

#javascript #tooltip #popup #dropdown 

Tippyjs: Tooltip, Popover, Dropdown, and Menu Library

A Flutter Package to Help You Beautify Your App Popups

flutter_beautiful_popup 中文

A flutter package to help you beautify your app popup, can be used in all platform.Live Demo.

Preview:

Getting Started

Add dependency to you pubspec.yaml:

dependencies:
    flutter_beautiful_popup: ^1.5.0

Import the dependency:

import 'package:flutter_beautiful_popup/main.dart';

And then you can display a popup with certain template like this:

final popup = BeautifulPopup(
  context: context,
  template: TemplateGift,
);
popup.show(
  title: 'String or Widget',
  content: 'String or Widget',
  actions: [
    popup.button(
      label: 'Close',
      onPressed: Navigator.of(context).pop,
    ),
  ],
  // bool barrierDismissible = false,
  // Widget close,
);

If you wan to recolor the illustration of the template, you can call the recolor method, but this function takes a little time to caculate/offset the color cahnnel of the illustration:

final newColor = Colors.red.withOpacity(0.5);
await popup.recolor(newColor);

All available templates you can find in Live Demo.

Customize your own BeautifulPopupTemplate

You can extend BeautifulPopupTemplate to customize your own template like this:

import 'package:flutter/material.dart';
import 'package:flutter_beautiful_popup/main.dart';

class MyTemplate extends BeautifulPopupTemplate {
  final BeautifulPopup options;
  MyTemplate(this.options) : super(options);

  @override
  final illustrationKey = 'images/mytemplate.png';
  @override
  Color get primaryColor => options.primaryColor ?? Color(0xff000000); // The default primary color of the template is Colors.black.
  @override
  final maxWidth = 400; // In most situations, the value is the illustration size.
  @override
  final maxHeight = 600;
  @override
  final bodyMargin = 10;

  // You need to adjust the layout to fit into your illustration.
  @override
  get layout {
    return [
      Positioned(
        child: background,
      ),
      Positioned(
        top: percentH(10),
        child: title,
      ),
      Positioned(
        top: percentH(40),
        height: percentH(actions == null ? 32 : 42),
        left: percentW(10),
        right: percentW(10),
        child: content,
      ),
      Positioned(
        bottom: percentW(10),
        left: percentW(10),
        right: percentW(10),
        child: actions ?? Container(),
      ),
    ];
  }
}

To display a popup with your own template:

final popup = BeautifulPopup.customize(
  context: context,
  build: (options) => MyTemplate(options),
);
popup.show(
  title: 'Example',
  content: Container(
    color: Colors.black12,
    child: Text(
        'This popup shows you how to customize your own BeautifulPopupTemplate.'),
  ),
  actions: [
    popup.button(
      label: 'Code',
      onPressed: () {
        js.context.callMethod('open', [
          'https://github.com/jaweii/Flutter_beautiful_popup/blob/master/example/lib/MyTemplate.dart'
        ]);
      },
    ),
  ],
);

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flutter_beautiful_popup

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flutter_beautiful_popup: ^1.7.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flutter_beautiful_popup/main.dart';
import 'package:flutter_beautiful_popup/templates/Authentication.dart';
import 'package:flutter_beautiful_popup/templates/BlueRocket.dart';
import 'package:flutter_beautiful_popup/templates/Camera.dart';
import 'package:flutter_beautiful_popup/templates/Coin.dart';
import 'package:flutter_beautiful_popup/templates/Common.dart';
import 'package:flutter_beautiful_popup/templates/Fail.dart';
import 'package:flutter_beautiful_popup/templates/Geolocation.dart';
import 'package:flutter_beautiful_popup/templates/Gift.dart';
import 'package:flutter_beautiful_popup/templates/GreenRocket.dart';
import 'package:flutter_beautiful_popup/templates/Notification.dart';
import 'package:flutter_beautiful_popup/templates/OrangeRocket.dart';
import 'package:flutter_beautiful_popup/templates/OrangeRocket2.dart';
import 'package:flutter_beautiful_popup/templates/RedPacket.dart';
import 'package:flutter_beautiful_popup/templates/Success.dart';
import 'package:flutter_beautiful_popup/templates/Term.dart';
import 'package:flutter_beautiful_popup/templates/Thumb.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter_beautiful_popup/main.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_highlight/flutter_highlight.dart';
import 'package:flutter_highlight/themes/github-gist.dart';
import 'package:url_launcher/url_launcher.dart';
import 'MyTemplate.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter_beautiful_popup',
      theme: ThemeData(primaryColor: Colors.blue),
      home: MyHomePage(title: 'Flutter_Beautiful_Popup'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  initState() {
    super.initState();
    final templates = [
      TemplateGift,
      TemplateCamera,
      TemplateNotification,
      TemplateGeolocation,
      TemplateSuccess,
      TemplateFail,
      // TemplateOrangeRocket,
      TemplateGreenRocket,
      TemplateOrangeRocket2,
      TemplateCoin,
      TemplateBlueRocket,
      TemplateThumb,
      TemplateAuthentication,
      TemplateTerm,
      TemplateRedPacket,
    ];

    demos = templates.map((template) {
      return BeautifulPopup(
        context: context,
        template: template,
      );
    }).toList();
  }

  List<BeautifulPopup> demos = [];

  BeautifulPopup? activeDemo;

  Widget get showcases {
    final popup = BeautifulPopup.customize(
      context: context,
      build: (options) => MyTemplate(options),
    );
    return Flex(
      mainAxisSize: MainAxisSize.max,
      direction: Axis.vertical,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Container(
          margin: EdgeInsets.fromLTRB(20, 20, 10, 10),
          decoration: BoxDecoration(
            border: Border(
              top: BorderSide(
                color: Colors.white,
                width: 1,
              ),
            ),
          ),
          child: Flex(
            direction: Axis.horizontal,
            children: <Widget>[
              Text(
                'All Templates:',
                style: Theme.of(context).textTheme.headline4?.merge(
                      TextStyle(
                        backgroundColor: Colors.transparent,
                      ),
                    ),
              ),
              Spacer(),
              FlatButton(
                child: Text('Customize'),
                onPressed: () {
                  popup.show(
                    title: 'Example',
                    content: Container(
                      color: Colors.black12,
                      child: Text(
                          'This popup shows you how to customize your own BeautifulPopupTemplate.'),
                    ),
                    actions: [
                      popup.button(
                        label: 'Code',
                        labelStyle: TextStyle(),
                        onPressed: () async {
                          await _launchURL(
                            'https://github.com/jaweii/Flutter_beautiful_popup/blob/master/example/lib/MyTemplate.dart',
                          );
                        },
                      ),
                    ],
                  );
                },
              )
            ],
          ),
        ),
        Expanded(
          child: SingleChildScrollView(
            padding: EdgeInsets.fromLTRB(20, 20, 0, 20),
            child: Wrap(
              alignment: WrapAlignment.start,
              spacing: 20,
              runSpacing: 30,
              children: demos.map((demo) {
                final i = demos.indexWhere((d) => d.template == demo.template);
                return InkWell(
                  borderRadius: BorderRadius.circular(10),
                  child: Container(
                    constraints: BoxConstraints(minWidth: 160),
                    padding: EdgeInsets.all(10),
                    decoration: BoxDecoration(
                      color: demo.primaryColor?.withOpacity(0.25),
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Image.asset(
                          demo.instance.illustrationKey,
                          height: 54,
                          width: 100,
                          fit: BoxFit.fitWidth,
                          alignment: Alignment.topCenter,
                        ),
                        SizedBox(height: 10),
                        Text(
                          'Demo-${i + 1}\n${demo.instance.runtimeType}',
                          textAlign: TextAlign.center,
                        )
                      ],
                    ),
                  ),
                  onTap: () {
                    openDemo(demo: demo);
                  },
                );
              }).toList(),
            ),
          ),
        ),
      ],
    );
  }

  Widget get body {
    final exampleCode = ''' 
final popup = BeautifulPopup(
  context: context,
  template: ${activeDemo?.instance.runtimeType ?? '// Select a template in right'},
);
                                                                  
popup.show(
  title: 'String',
  content: 'BeautifulPopup is a flutter package that is responsible for beautify your app popups.',
  actions: [
    popup.button(
      label: 'Close',
      onPressed: Navigator.of(context).pop,
    ),
  ],
);
    ''';
    if (MediaQuery.of(context).size.width > 1024) {
      return Flex(
        direction: Axis.horizontal,
        children: <Widget>[
          Flexible(
            flex: 1,
            fit: FlexFit.tight,
            child: Container(
              color: activeDemo?.primaryColor?.withOpacity(0.25) ??
                  Theme.of(context).primaryColor.withOpacity(0.25),
              child: Flex(
                mainAxisSize: MainAxisSize.max,
                direction: Axis.vertical,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Container(
                    margin: EdgeInsets.fromLTRB(20, 20, 10, 10),
                    child: Text(
                      '# Usage',
                      style: Theme.of(context).textTheme.headline4?.merge(
                            TextStyle(
                              color: Colors.black54,
                              backgroundColor: Colors.transparent,
                            ),
                          ),
                    ),
                  ),
                  Expanded(
                    child: Container(
                      alignment: Alignment.center,
                      child: HighlightView(
                        exampleCode,
                        language: 'dart',
                        theme: githubGistTheme,
                        padding: EdgeInsets.all(30),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
          Flexible(
            flex: 1,
            fit: FlexFit.tight,
            child: showcases,
          ),
        ],
      );
    } else {
      return showcases;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          widget.title,
          style: TextStyle(color: Colors.white),
        ),
        elevation: 2,
        backgroundColor:
            activeDemo?.primaryColor ?? Theme.of(context).primaryColor,
        actions: <Widget>[
          FlatButton(
            child: Image.asset(
              'images/github.png',
              width: 32,
              height: 32,
            ),
            onPressed: () async {
              await _launchURL(
                'https://github.com/jaweii/Flutter_beautiful_popup',
              );
            },
          ),
        ],
      ),
      body: body,
    );
  }

  void changeColor(
    BeautifulPopup demo,
    void Function(Color? color)? callback,
  ) {
    Color? color = demo.primaryColor?.withOpacity(0.5);
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Pick a color!'),
        content: SingleChildScrollView(
          child: ColorPicker(
            pickerColor: color == null ? Color(0xFF000000) : color!,
            onColorChanged: (c) => color = c,
            showLabel: true,
            pickerAreaHeightPercent: 0.8,
          ),
        ),
        actions: <Widget>[
          FlatButton(
            child: const Text('Got it'),
            onPressed: () async {
              callback?.call(color);
            },
          ),
        ],
      ),
    );
  }

  openDemo({
    required BeautifulPopup demo,
    dynamic title = 'String',
    dynamic content =
        'BeautifulPopup is a flutter package that is responsible for beautify your app popups.',
  }) {
    assert(title is Widget || title is String);
    setState(() {
      activeDemo = demo;
    });
    demo.show(
      title: title,
      content: content,
      actions: <Widget>[
        demo.button(
          label: 'Recolor',
          onPressed: () {
            changeColor(demo, (color) async {
              demo = await BeautifulPopup(
                context: context,
                template: demo.template,
              ).recolor(color!);
              Navigator.of(context).popUntil((route) {
                if (route.settings.name == '/') return true;
                return false;
              });
              openDemo(demo: demo);
            });
          },
        ),
        demo.button(
          label: 'Show more',
          outline: true,
          onPressed: () {
            Navigator.of(context).pop();
            if (title is Widget) {
              return openDemo(demo: demo);
            }
            getTitle() {
              return Opacity(
                opacity: 0.95,
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    Text(
                      '[Widget]',
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 20,
                        color: demo.primaryColor,
                        backgroundColor: Colors.white70,
                      ),
                    ),
                    Padding(
                      padding: EdgeInsets.only(top: 20),
                      child: Icon(
                        Icons.star,
                        color: demo.primaryColor?.withOpacity(0.75),
                        size: 10,
                      ),
                    )
                  ],
                ),
              );
            }

            getContent() {
              return Container(
                decoration: BoxDecoration(
                  color: Colors.black.withOpacity(0.1),
                ),
                child: Scrollbar(
                  child: SingleChildScrollView(
                    child: Column(
                      children: <Widget>[
                        CupertinoButton(
                          child: Text('Remove all buttons'),
                          onPressed: () {
                            Navigator.of(context).pop();
                            demo = BeautifulPopup(
                              context: context,
                              template: demo.template,
                            );
                            demo.show(
                              title: getTitle(),
                              content: getContent(),
                              actions: [],
                            );
                          },
                        ),
                        CupertinoButton(
                          child: Text('Keep one button'),
                          onPressed: () {
                            Navigator.of(context).pop();
                            demo = BeautifulPopup(
                              context: context,
                              template: demo.template,
                            );
                            demo.show(
                              title: getTitle(),
                              content: getContent(),
                              actions: [
                                demo.button(
                                  label: 'One button',
                                  onPressed: () {
                                    Navigator.of(context).pop();
                                  },
                                ),
                              ],
                            );
                          },
                        ),
                        CupertinoButton(
                          child: Text('Remove Close button'),
                          onPressed: () {
                            Navigator.of(context).pop();
                            demo = BeautifulPopup(
                              context: context,
                              template: demo.template,
                            );
                            demo.show(
                              title: getTitle(),
                              content: getContent(),
                              close: Container(),
                              barrierDismissible: true,
                              actions: [
                                demo.button(
                                  label: 'Close',
                                  onPressed: () {
                                    Navigator.of(context).pop();
                                  },
                                ),
                              ],
                            );
                          },
                        ),
                        CupertinoButton(
                          child: Text('Change button direction'),
                          onPressed: () {
                            Navigator.of(context).pop();
                            demo = BeautifulPopup(
                              context: context,
                              template: demo.template,
                            );
                            demo.show(
                              title: getTitle(),
                              content: Flex(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                direction: Axis.vertical,
                                children: <Widget>[
                                  Text('1. blabla... \n2. blabla...'),
                                  Spacer(),
                                  demo.button(
                                    label: 'Accpet',
                                    onPressed: () {},
                                  ),
                                  Container(
                                    alignment: Alignment.center,
                                    child: FlatButton(
                                      hoverColor: Colors.transparent,
                                      highlightColor: Colors.transparent,
                                      child: Text('Close'),
                                      onPressed: Navigator.of(context).pop,
                                    ),
                                  ),
                                ],
                              ),
                              barrierDismissible: true,
                              actions: [],
                            );
                          },
                        )
                      ],
                    ),
                  ),
                ),
              );
            }

            openDemo(
              demo: demo,
              title: getTitle(),
              content: getContent(),
            );
          },
        )
      ],
    );
  }

  Future<void> _launchURL(String _url) async {
    await canLaunch(_url) ? await launch(_url) : throw 'Could not launch $_url';
  }
} 

Download Details:

Author: 

Source Code: https://pub.dev/packages/flutter_beautiful_popup

#flutter #popup 

A Flutter Package to Help You Beautify Your App Popups

Modal Popup using HTML CSS JavaScript | Modal Popup Tutorial

A Modal Popup window is a child window that requires users to interact with it before they can return to operating the parent application.

This video walk through you step step about how Create Modal using HTML, CSS and JavaScript. As part of this video

Timeline :

01:33 Create Markup using HTML
04:22 Style Modal Popup using CSS
12:10 JavaScript Starts
16:35 Adding Blur effect

#html  #css  #javascript #modal #popup

https://youtu.be/MdNUhQOFeBg

Modal Popup using HTML CSS JavaScript | Modal Popup Tutorial
anita maity

anita maity

1623388635

Popup Login Form Design Using HTML and CSS

The pop-up login form is a modern type of login form design that is very popular nowadays. In the case of this type of design, the login form is completely hidden. Normally we see a button or link. Clicking on that link shows the complete login form design. There is a cancel button that, when clicked, hides the log form again.

Demo & Download Code

#popup-login-form #popup #login-form #html #css

Popup Login Form Design Using HTML and CSS
Elian  Harber

Elian Harber

1615435717

Modal Popup Window in Blazor WebAssembly

Introduction

Sometime in our web application we may need to display contents in Popup Window. A popup window is a web browser window that is smaller than standard windows and without some of the standard features such as toolbars or status bars. Popups are one of the trickiest effects in web development, but in Blazor WebAssembly we can create it in simple way. All we need to Install a NuGet Package called, BlazoredModal. A BlazoredModal is a powerful and customizable modal implementation for Blazor applications.

Getting Started – Initial Setup
Creating a new Project
  • Start and navigate to Visual Studio, in my case its VS 2019.
  • Choose Create a new project option

Fig.1 Choose Create a new project option from Visual Studio

#blazor #modal popup #popup #wasm popup

Modal Popup Window in Blazor WebAssembly

Aman Agrawal

1606207037

Animate the modal popup using CSS

Once you’re done creating your css popup. We’re now going to animate it with CSS3. Why? because we’re tired of seeing things that just pop onto users screen and you don’t know where it came from. Also, to make it fun for your users. Let’s get started.

https://www.loginradius.com/engineering/blog/animating-simple-css-popup-tutorial/

#slide #css #swirl #popup #programming #engineering

Animate the modal popup using CSS