UIWidget is a Unity Package which helps developers to create, debug and deploy efficient, cross-platform Apps.

Overview

⚠️ The main repository of UIWidgets has been moved to https://github.com/Unity-Technologies/com.unity.uiwidgets. Please visit the new site if you have an issue or want to contribute. Thanks!

UIWidgets

中文

Introduction

UIWidgets is a plugin package for Unity Editor which helps developers to create, debug and deploy efficient, cross-platform Apps using the Unity Engine.

UIWidgets is mainly derived from Flutter. However, taking advantage of the powerful Unity Engine, it offers developers many new features to improve their Apps as well as the develop workflow significantly.

Efficiency

Using the latest Unity rendering SDKs, a UIWidgets App can run very fast and keep >60fps in most times.

Cross-Platform

A UIWidgets App can be deployed on all kinds of platforms including PCs, mobile devices and web page directly, like any other Unity projects.

Multimedia Support

Except for basic 2D UIs, developers are also able to include 3D Models, audios, particle-systems to their UIWidgets Apps.

Developer-Friendly

A UIWidgets App can be debug in the Unity Editor directly with many advanced tools like CPU/GPU Profiling, FPS Profiling.

Example

Projects using UIWidgets

Unity Connect App

The Unity Connect App is created using UIWidgets and available for both Android (https://connect.unity.com/connectApp/download) and iOS (Searching for "Unity Connect" in App Store). This project is open-sourced @https://github.com/UnityTech/ConnectAppCN.

Unity Chinese Doc

The official website of Unity Chinese Documentation (https://connect.unity.com/doc) is powered by UIWidgets and open-sourced @https://github.com/UnityTech/DocCN.

Requirements

Unity

Install Unity 2018.4.10f1 (LTS) or Unity 2019.1.14f1 and above. You can download the latest Unity on https://unity3d.com/get-unity/download.

UIWidgets Package

Visit our Github repository https://github.com/UnityTech/UIWidgets to download the latest UIWidgets package.

Move the downloaded package folder into the Package folder of your Unity project.

Generally, you can make it using a console (or terminal) application by just a few commands as below:

 cd <YourProjectPath>/Packages
 git clone https://github.com/UnityTech/UIWidgets.git com.unity.uiwidgets

Getting Start

i. Overview

In this tutorial, we will create a very simple UIWidgets App as the kick-starter. The app contains only a text label and a button. The text label will count the times of clicks upon the button.

First of all, please open or create a Unity Project and open it with Unity Editor.

And then open Project Settings, go to Player section and add "UIWidgets_DEBUG" to the Scripting Define Symbols field. This enables the debug mode of UIWidgets for your development. Remove this for your release build afterwards.

ii. Scene Build

A UIWidgets App is usually built upon a Unity UI Canvas. Please follow the steps to create a UI Canvas in Unity.

  1. Create a new Scene by "File -> New Scene";
  2. Create a UI Canvas in the scene by "GameObject -> UI -> Canvas";
  3. Add a Panel (i.e., Panel 1) to the UI Canvas by right click on the Canvas and select "UI -> Panel". Then remove the Image Component from the Panel.

iii. Create Widget

A UIWidgets App is written in C# Scripts. Please follow the steps to create an App and play it in Unity Editor.

  1. Create a new C# Script named "UIWidgetsExample.cs" and paste the following codes into it.

     using System.Collections.Generic;
     using Unity.UIWidgets.animation;
     using Unity.UIWidgets.engine;
     using Unity.UIWidgets.foundation;
     using Unity.UIWidgets.material;
     using Unity.UIWidgets.painting;
     using Unity.UIWidgets.ui;
     using Unity.UIWidgets.widgets;
     using UnityEngine;
     using FontStyle = Unity.UIWidgets.ui.FontStyle;
    
     namespace UIWidgetsSample {
         public class UIWidgetsExample : UIWidgetsPanel {
             protected override void OnEnable() {
                 // if you want to use your own font or font icons.
                 // FontManager.instance.addFont(Resources.Load<Font>(path: "path to your font"), "font family name");
    
                 // load custom font with weight & style. The font weight & style corresponds to fontWeight, fontStyle of
                 // a TextStyle object
                 // FontManager.instance.addFont(Resources.Load<Font>(path: "path to your font"), "Roboto", FontWeight.w500,
                 //    FontStyle.italic);
    
                 // add material icons, familyName must be "Material Icons"
                 // FontManager.instance.addFont(Resources.Load<Font>(path: "path to material icons"), "Material Icons");
    
                 base.OnEnable();
             }
    
             protected override Widget createWidget() {
                 return new WidgetsApp(
                     home: new ExampleApp(),
                     pageRouteBuilder: (RouteSettings settings, WidgetBuilder builder) =>
                         new PageRouteBuilder(
                             settings: settings,
                             pageBuilder: (BuildContext context, Animation<float> animation,
                                 Animation<float> secondaryAnimation) => builder(context)
                         )
                 );
             }
    
             class ExampleApp : StatefulWidget {
                 public ExampleApp(Key key = null) : base(key) {
                 }
    
                 public override State createState() {
                     return new ExampleState();
                 }
             }
    
             class ExampleState : State<ExampleApp> {
                 int counter = 0;
    
                 public override Widget build(BuildContext context) {
                     return new Column(
                         children: new List<Widget> {
                             new Text("Counter: " + this.counter),
                             new GestureDetector(
                                 onTap: () => {
                                     this.setState(()
                                         => {
                                         this.counter++;
                                     });
                                 },
                                 child: new Container(
                                     padding: EdgeInsets.symmetric(20, 20),
                                     color: Colors.blue,
                                     child: new Text("Click Me")
                                 )
                             )
                         }
                     );
                 }
             }
         }
     }
  2. Save this script and attach it to Panel 1 as its component.

  3. Press the "Play" Button to start the App in Unity Editor.

iv. Build App

Finally, the UIWidgets App can be built to packages for any specific platform by the following steps.

  1. Open the Build Settings Panel by "File -> Build Settings..."
  2. Choose a target platform and click "Build". Then the Unity Editor will automatically assemble all relevant resources and generate the final App package.

How to load images?

  1. Put your images files in Resources folder. e.g. image1.png.
  2. You can add [email protected] and [email protected] in the same folder to support HD screens.
  3. Use Image.asset("image1") to load the image. Note: as in Unity, ".png" is not needed.

UIWidgets supports Gif as well!

  1. Suppose you have loading1.gif. Rename it to loading1.gif.bytes and copy it to Resources folder.
  2. You can add [email protected] and [email protected] in the same folder to support HD screens.
  3. Use Image.asset("loading1.gif") to load the gif images.

Using Window Scope

If you see the error AssertionError: Window.instance is null or null pointer error of Window.instance, it means the code is not running in the window scope. In this case, you can enclose your code with window scope as below:

using(WindowProvider.of(your gameObject with UIWidgetsPanel).getScope()) {
    // code dealing with UIWidgets,
    // e.g. setState(() => {....})
}

This is needed if the code is in methods not invoked by UIWidgets. For example, if the code is in completed callback of UnityWebRequest, you need to enclose them with window scope. Please see HttpRequestSample for detail. For callback/event handler methods from UIWidgets (e.g Widget.build, State.initState...), you don't need do it yourself, since the framework ensure it's in window scope.

Show Status Bar on Android

Status bar is always hidden by default when an Unity project is running on an Android device. If you want to show the status bar in your App, this solution seems to be compatible to UIWidgets, therefore can be used as a good option before we release our full support solution on this issue.

Besides, please set "Render Outside Safe Area" to true in the "Player Settings" to make this plugin working properly on Android P or later.

Automatically Adjust Frame Rate

To build an App that is able to adjust the frame rate automatically, please open Project Settings, and in the Quality tab, set the "V Sync Count" option of the target platform to "Don't Sync". The default logic is to reduce the frame rate when the screen is static, and change it back to 60 whenever the screen changes. If you would like to disable this behavior, please set Window.onFrameRateSpeedUp and Window.onFrameRateCoolDown to null function, i.e., () => {}.

Note that in Unity 2019.3 and above, UIWidgets will use OnDemandRenderAPI to implement this feature, which will greatly save the battery.

WebGL Canvas Device Pixel Ratio Plugin

The width and height of the Canvas in browser may differ from the number of pixels the Canvas occupies on the screen. Therefore, the image may blur in the builded WebGL program. The Plugin Plugins/platform/webgl/UIWidgetsCanvasDevicePixelRatio_20xx.x.jslib (2018.3 and 2019.1 for now) solves this issue. Please select the plugin of the Unity version corresponding to your project, and disable other versions of this plugin, as follows: select this plugin in the Project panel, and uncheck WebGL under Select platforms for plugin in the Inspector panel. If you need to disable this plugin for any reason, please disable all the versions of this plugin as described above.

This plugin overrides the following parameters in the Unity WebGL building module:

JS_SystemInfo_GetWidth
JS_SystemInfo_GetHeight
JS_SystemInfo_GetCurrentCanvasWidth
JS_SystemInfo_GetCurrentCanvasHeight
$Browser
$JSEvents

If you would like to implement your own WebGL plugin, and your plugin overrides at least one of the above parameters, you need to disable the UIWidgetsCanvasDevicePixelRatio plugin in the above mentioned way to avoid possible conflicts. If you still need the function provided by this plugin, you can mannually apply the modification to Unity WebGL building module introduced in this plugin. All the modifications introduced in UIWidgetsCanvasDevicePixelRatio are marked by ////////// Modifcation Start //////////// and ////////// Modifcation End ////////////. In the marked codes, all the multiplications and divisions with devicePixelRatio are introduced by our modification. To learn about the original script in detail, please refer to SystemInfo.js and UnityNativeJS/UnityNative.js in PlaybackEngines/WebGLSupport/BuildTools/lib in your Unity Editor installation.

Image Import Setting

Unity, by default, resizes the width and height of an imported image to the nearest integer that is a power of 2. In UIWidgets, you should almost always disable this by selecting the image in the "Project" panel, then in the "Inspector" panel set the "Non Power of 2" option (in "Advanced") to "None", to prevent your image from being resized unexpectedly.

Update Emoji

UIWidgets supports rendering emoji in (editable) texts. The default emoji resource version is iOS 13.2. We also prepared the resources of Google Emoji. To switch to Google version of emoji, please follow the following steps:

  1. Copy Runtime/Resources/backup~/EmojiGoogle.png to Runtime/Resources/images folder.
  2. In the Project panel, find and select EmojiGoogle asset, and in the Inspector panel, change Max Size to 4096, disable Generate Mipmaps, and enable Alpha Is Transparency.
  3. In the OnEnable() function in your class overriding UIWidgetsPanel, add the following code
EmojiUtils.configuration = EmojiUtils.googleEmojiConfiguration;

If you would like to use your own images for emoji, please follow the following steps:

  1. Create the sprite sheet (take EmojiGoogle.png as an example), and put in a Resources folder in your project, (for example Resources/myImages/MyEmoji.png).
  2. In the OnEnable() function, add the following code (replace example values with actual value). Note that the order of emoji codes should be consistent with the sprite sheet.
EmojiUtils.configuration = new EmojiResourceConfiguration(
  spriteSheetAssetName: "myImage/MyEmoji",
  emojiCodes: new List<int> {
    0x1f004, 0x1f0cf, 0x1f170, ...
  },
  spriteSheetNumberOfRows: 36,
  spriteSheetNumberOfColumns: 37,
);

Interact with GameObject Drag&Drops

With the provided packaged stateful widget UnityObjectDetector and its onRelease callback function, you can easily drag some objects (for example GameObject from Hierarchy, files from Project Window, etc) into the area, get the UnityEngine.Object[] references and make further modification.

Debug UIWidgets Application

Define UIWidgets_DEBUG

It's recommended to define the UIWidgets_DEBUG script symbol in editor, this will turn on debug assertion in UIWidgets, which will help to find potential bugs earlier. To do this: please go to Player Settings -> Other Settings -> Configuration -> Scripting Define Symbols, and add UIWidgets_DEBUG. The symbol is for debug purpose, please remove it from your release build.

UIWidgets Inspector

The UIWidgets Inspector tool is for visualizing and exploring the widget trees. You can find it via Window/Analysis/UIWidgets inspector in Editor menu.

Note

  • UIWidgets_DEBUG needs to be define for inspector to work properly.
  • Inspector currently only works in Editor Play Mode, inspect standalone built application is not supported for now.

Learn

Samples

You can find many UIWidgets sample projects on Github, which cover different aspects and provide you learning materials in various levels:

  • UIWidgetsSamples (https://github.com/UIWidgets/UIWidgetsSamples). These samples are developed by the dev team in order to illustrates all the features of UIWidgets. First clone this Repo to the Assets folder of your local UIWidgets project. Then you can find all the sample scenes under the Scene folder. You can also try UIWidgets-based Editor windows by clicking the new UIWidgetsTests tab on the main menu and open one of the dropdown samples.
  • awesome-UIWidgets by Liangxie (https://github.com/liangxiegame/awesome-uiwidgets). This Repo contains lots of UIWidget demo apps and third-party applications.
  • ConnectApp (https://github.com/UnityTech/ConnectAppCN). This is an online, open-source UIWidget-based App developed by the dev team. If you are making your own App with UIWidgets, this project will provides you with many best practice cases.

Wiki

The develop team is still working on the UIWidgets Wiki. However, since UIWidgets is mainly derived from Flutter, you can refer to Flutter Wiki to access detailed descriptions of UIWidgets APIs from those of their Flutter counterparts. Meanwhile, you can join the discussion channel at (https://connect.unity.com/g/uiwidgets)

FAQ

Question Answer
Can I create standalone App using UIWidgets? Yes
Can I use UIWidgets to build game UIs? Yes
Can I develop Unity Editor plugins using UIWidgets? Yes
Is UIWidgets a extension of UGUI/NGUI? No
Is UIWidgets just a copy of Flutter? No
Can I create UI with UIWidgets by simply drag&drop? No
Do I have to pay for using UIWidgets? No
Any IDE recommendation for UIWidgets? Rider, VSCode(Open .sln)

How to Contribute

Check CONTRIBUTING.md

Comments
  • UIWidgets 性能问题

    UIWidgets 性能问题

    TL; DR:当前的 UIWidgets 代码仓库是否存在性能问题?如果是的话,未来大概什么时候会优化?

    最近尝试学习 UIWidgets,发现自己写的示例 app 即使非常简单,也会有非常肉眼可见的性能问题,比如说: 1)用 PageView 切换页面时很卡 2)Switch Widgets 的动画很卡

    用 graphy 看了看,确实在上述两种场景下 fps 会掉得特别厉害 由于在 Editor 上能流畅运行,一开始觉得是自己测试机性能太差,但【ConnectApp】是能流畅运行的,所以怀疑是实现的问题 上网查了查,用上了一些常用的小优化,问题没有得到解决 后面把官方的【Gallery】打包下来试了试,发现【性能问题更加严重】,所以又怀疑是这边的 UIWidgets 并不是最新版、又或是直接用 unity 打包本身会存在性能问题 看了看 issue,有提到动态 fps,有提到未来会把 ConnectApp 那边的功能迁移过来,所以我这边也不好判断到底是我写拐了还是说当前的 UIWidgets 尚未成熟 所以就回到抬头的问题了:当前的 UIWidgets 代码仓库是否存在性能问题?如果是的话,未来大概什么时候会优化?

    question 
    opened by carefree0910 17
  • AssertionError: Error caught by scheduler library, thrown during a scheduler callback.

    AssertionError: Error caught by scheduler library, thrown during a scheduler callback.

    使用 Packages\com.unity.uiwidgets\Samples\UIWidgetSample\TextInput.unity 场景输出到安卓机上运行,打开部分页面会报如下错误: 2019-10-18 15:07:12.389 8937-8955/? E/Unity: AssertionError: Error caught by scheduler library, thrown during a scheduler callback. unmatched save/restore commands at Unity.UIWidgets.ui.uiPictureRecorder.endRecording () [0x0000e] in :0 at Unity.UIWidgets.ui.CommandBufferCanvas.flush () [0x00000] in :0 at Unity.UIWidgets.editor.WindowSurfaceImpl._presentSurface (Unity.UIWidgets.ui.Canvas canvas) [0x00010] in :0 at Unity.UIWidgets.editor.WindowSurfaceImpl.b__9_0 (Unity.UIWidgets.editor.SurfaceFrame frame, Unity.UIWidgets.ui.Canvas canvas) [0x00000] in :0 at Unity.UIWidgets.editor.SurfaceFrame._performSubmit () [0x00017] in :0 at Unity.UIWidgets.editor.SurfaceFrame.submit () [0x0000a] in :0 at Unity.UIWidgets.editor.Rasterizer._drawToSurface (Unity.UIWidgets.flow.LayerTree layerTree) [0x0004e] in <d683ce45a0b6415ca62a1b21 issue01.txt

    bug 
    opened by lyq248739402 12
  • 不能在异步函数的回调中 setState

    不能在异步函数的回调中 setState

    NullReferenceException: Object reference not set to an instance of an object
    Unity.UIWidgets.scheduler.SchedulerBinding.scheduleFrame () (at Packages/com.unity.uiwidgets/Runtime/scheduler/binding.cs:184)
    Unity.UIWidgets.scheduler.SchedulerBinding.ensureVisualUpdate () (at Packages/com.unity.uiwidgets/Runtime/scheduler/binding.cs:162)
    Unity.UIWidgets.widgets.WidgetsBinding._handleBuildScheduled () (at Packages/com.unity.uiwidgets/Runtime/widgets/binding.cs:108)
    Unity.UIWidgets.widgets.BuildOwner.scheduleBuildFor (Unity.UIWidgets.widgets.Element element) (at Packages/com.unity.uiwidgets/Runtime/widgets/framework.cs:891)
    Unity.UIWidgets.widgets.Element.markNeedsBuild () (at Packages/com.unity.uiwidgets/Runtime/widgets/framework.cs:2044)
    Unity.UIWidgets.widgets.State.setState (Unity.UIWidgets.ui.VoidCallback fn) (at Packages/com.unity.uiwidgets/Runtime/widgets/framework.cs:510)
    BookListState.<RequestBooks>b__2_0 (System.Object response) (at Assets/Scripts/BookListPage.cs:45)
    HTTPHelper+<GetAsync>d__8`1[T].MoveNext () (at Assets/Scripts/HTTPHelper.cs:82)
    --- End of stack trace from previous location where exception was thrown ---
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) (at <d7ac571ca2d04b2f981d0d886fa067cf>:0)
    UnityEngine.UnitySynchronizationContext+WorkRequest.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnitySynchronizationContext.cs:115)
    UnityEngine.UnitySynchronizationContext:ExecuteTasks()
    

    用 HTTPClient 异步发 Get 请求,在回调函数中 setState 报上面的错误。 具体仓库在 UIWidget-Practice,报错行数在 这里

    还是说我写的姿势不对?

    opened by Latias94 10
  • Listener的事件触发异常

    Listener的事件触发异常

    Listener的onPointerEnter和onPointerExit触发时报错。 代码如下:

    public abstract class AUIWidgetsPanel : UIWidgetsPanel, ICanvasRaycastFilter
        {
            public abstract Widget Home { get; }
    
            private Texture2D texture2D;
            private int width;
            private int height;
            private Vector2 local;
            private Rect rect;
    
            protected override void OnEnable()
            {
                base.OnEnable();
                UpdateSize();
            }
    
            private void UpdateSize()
            {
                RectTransform rectTransform = this.GetComponent<RectTransform>();
                int newWidth = (int)rectTransform.rect.width;
                int newHeight = (int)rectTransform.rect.height;
    
                if (this.width != newWidth || this.height != newHeight)
                {
                    this.width = newWidth;
                    this.height = newHeight;
    
                    this.texture2D = new Texture2D(this.width, this.height, TextureFormat.RGBA32, false);
                }
            }
    
            protected override void OnRectTransformDimensionsChange()
            {
                base.OnRectTransformDimensionsChange();
                UpdateSize();
            }
    
            public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
            {
                if (!this.isActiveAndEnabled)
                {
                    return true;
                }
    
                RectTransformUtility.ScreenPointToLocalPointInRectangle(this.rectTransform, sp, eventCamera, out local);
                rect = this.rectTransform.rect;
                local.x += this.rectTransform.pivot.x * rect.width;
                local.y += this.rectTransform.pivot.y * rect.height;
                uvRect = this.uvRect;
                float u = local.x / rect.width * uvRect.width + uvRect.x;
                float v = local.y / rect.height * uvRect.height + uvRect.y;
    
                RenderTexture.active = this.texture as RenderTexture;
                texture2D.ReadPixels(new Rect(0, 0, this.width, this.height), 0, 0);
                texture2D.Apply();
    
                return texture2D.GetPixelBilinear(u, v).a != 0;
            }
    
            protected override Widget createWidget()
            {
                return new MaterialApp(
                    home: this.Home
                    );
            }
        }
    
    public class PenItem : AUIWidgetsPanel
        {
            public bool IsSelected;
    
            public override Widget Home => new PenItemWidget(this);
    
            public PenItem Reduce(PenItem state, object action)
            {
                if (action is bool selected)
                {
                    state.IsSelected = selected;
                }
                return state;
            }
        }
    
        public class PenItemWidget : StatelessWidget
        {
            private Store<PenItem> store;
    
            public PenItemWidget(PenItem panel)
            {
                this.store = new Store<PenItem>(panel.Reduce, panel);
            }
    
            public override Widget build(BuildContext context)
            {
                return new ScreenAdapter(
                    context: context,
                    child: new StoreProvider<PenItem>(
                        store: this.store,
                        child: new StoreConnector<PenItem, bool>(
                            converter: state => state.IsSelected,
                            builder: (builderContext, value, dispatcher) => build(builderContext, value, dispatcher)
                            )
                        )
                    );
            }
    
            public Widget build(BuildContext context, bool state, Dispatcher dispatcher)
            {
                return new Stack(
                    children: new List<Widget>
                    {
                        new Listener(
                            behavior: Unity.UIWidgets.rendering.HitTestBehavior.opaque,
                            child:new Container(
                                alignment:Alignment.bottomCenter,
                                child:AddressableAssetImage.addressable(Address.UISprite_电压表笔_黑)
                                ),
                            onPointerEnter:_ => dispatcher.dispatch(true),
                            onPointerExit:_ => dispatcher.dispatch(false)
                            ),
                        new Align(
                            alignment:Alignment.bottomCenter,
                            child:AddressableAssetImage.addressable(state ? Address.UISprite_电压表笔_light_select : Address.UISprite_电压表笔_light_normal)
                            ),
                    }
                    );
            }
        }
    

    运行报错截图: TIM

    详细报错信息: AssertionError: Error caught by widgets library, thrown while rebuilding dirty elements. The element being rebuilt at the time was index 0 of 1: Unity.UIWidgets.Redux._StoreListener2[ETModel.PenItem,System.Boolean](state:Unity.UIWidgets.Redux._StoreListenerState2[ETModel.PenItem,System.Boolean]#D3E00) at Unity.UIWidgets.widgets.Element.rebuild () [0x000a2] in E:\RD-NE19042\Unity\Library\PackageCache\[email protected]\Runtime\widgets\framework.cs:2085 at Unity.UIWidgets.widgets.BuildOwner.buildScope (Unity.UIWidgets.widgets.Element context, Unity.UIWidgets.ui.VoidCallback callback) [0x001b9] in E:\RD-NE19042\Unity\Library\PackageCache\[email protected]\Runtime\widgets\framework.cs:997 Unity.UIWidgets.widgets.Element.rebuild () (at Library/PackageCache/[email protected]/Runtime/widgets/framework.cs:2085) Unity.UIWidgets.widgets.BuildOwner.buildScope (Unity.UIWidgets.widgets.Element context, Unity.UIWidgets.ui.VoidCallback callback) (at Library/PackageCache/[email protected]/Runtime/widgets/framework.cs:997) UnityEngine.Debug:LogException(Exception) Unity.UIWidgets.foundation.D:logError(String, Exception) (at Library/PackageCache/[email protected]/Runtime/foundation/debug.cs:15) Unity.UIWidgets.foundation.UIWidgetsError:dumpErrorToConsole(UIWidgetsErrorDetails, Boolean) (at Library/PackageCache/[email protected]/Runtime/foundation/assertions.cs:120) Unity.UIWidgets.foundation.UIWidgetsError:dumpErrorToConsole(UIWidgetsErrorDetails) (at Library/PackageCache/[email protected]/Runtime/foundation/assertions.cs:105) Unity.UIWidgets.foundation.UIWidgetsError:reportError(UIWidgetsErrorDetails) (at Library/PackageCache/[email protected]/Runtime/foundation/assertions.cs:131) Unity.UIWidgets.widgets.WidgetsD:_debugReportException(String, Exception, InformationCollector) (at Library/PackageCache/[email protected]/Runtime/widgets/debug.cs:140) Unity.UIWidgets.widgets.BuildOwner:buildScope(Element, VoidCallback) (at Library/PackageCache/[email protected]/Runtime/widgets/framework.cs:1000) Unity.UIWidgets.widgets.WidgetsBinding:drawFrame() (at Library/PackageCache/[email protected]/Runtime/widgets/binding.cs:150) Unity.UIWidgets.rendering.RendererBinding:_handlePersistentFrameCallback(TimeSpan) (at Library/PackageCache/[email protected]/Runtime/rendering/binding.cs:73) Unity.UIWidgets.scheduler.SchedulerBinding:_invokeFrameCallback(FrameCallback, TimeSpan, String) (at Library/PackageCache/[email protected]/Runtime/scheduler/binding.cs:356) Unity.UIWidgets.scheduler.SchedulerBinding:handleDrawFrame() (at Library/PackageCache/[email protected]/Runtime/scheduler/binding.cs:297) Unity.UIWidgets.scheduler.SchedulerBinding:_handleDrawFrame() (at Library/PackageCache/[email protected]/Runtime/scheduler/binding.cs:234) Unity.UIWidgets.editor.WindowAdapter:_beginFrame() (at Library/PackageCache/[email protected]/Runtime/editor/editor_window.cs:330) Unity.UIWidgets.editor.WindowAdapter:_doOnGUI(Event) (at Library/PackageCache/[email protected]/Runtime/editor/editor_window.cs:338) Unity.UIWidgets.editor.WindowAdapter:OnGUI(Event) (at Library/PackageCache/[email protected]/Runtime/editor/editor_window.cs:307) Unity.UIWidgets.engine.UIWidgetWindowAdapter:OnGUI(Event) (at Library/PackageCache/[email protected]/Runtime/engine/UIWidgetsPanel.cs:54) Unity.UIWidgets.engine.UIWidgetsPanel:Update() (at Library/PackageCache/[email protected]/Runtime/engine/UIWidgetsPanel.cs:231)

    question 
    opened by liusujin 7
  • 使用TextField报错

    使用TextField报错

    新建了一个TextField 只要点击输入框就会报错

    public class UIChatScreen : StatefulWidget
    {
        public override State createState()
        {
            return new ChatScreen();
        }
    }
    
    public class ChatScreen : State<StatefulWidget>
    {
    
        TextEditingController controller = new TextEditingController();
        FocusNode _focusNode = new FocusNode();
        public override void initState()
        {
            base.initState();
    
            _focusNode.addListener(focusListener);
        }
    
        void focusListener()
        {
            UnityEngine.Debug.LogError(_focusNode.hasFocus);
        }
    
        public override Widget build(BuildContext context)
        {
            return new Container(
                width: 550f,
                height:50,
                alignment:Alignment.center,
                child: new TextField(
                    focusNode: _focusNode,
                    style: new TextStyle(
                        color: Color.fromARGB(255, 255, 238, 204),
                        fontSize: 20,
                        decoration: TextDecoration.none,
                        fontWeight: FontWeight.normal
                        ),
                    controller: controller
                    )
                );
        }
    }
    

    image

    opened by songcy950605 6
  • Wrong scale and wrong drawing

    Wrong scale and wrong drawing

    Hi! Wrong scale and wrong drawing, I repeated the example https://www.youtube.com/watch?v=5KbiU-93-yU , but the display is not correct, everything is small, the buttons have a rounding wrong, the picture in the favorite item is also not correct drawn

    Bug Video: https://monosnap.com/file/H87LBr2xudui0tKENfmtHhFsI1rBR9

    Unity 2019.1 Unity Project: https://drive.google.com/open?id=1yUTlIVfLpGKG4QceutsUeTx-4SNWp39W Flutter Project: https://github.com/devefy/Flutter-Story-App-UI

    opened by Avatarchik 5
  • UIWidgets 显示问题

    UIWidgets 显示问题

    在我将项目中的【Asset Store】版本的 UIWidgets,换成【master branch】 的版本并导入到 Packages 中后,发现在手机屏幕抬头处有较为明显的显示问题(【之前是不存在的】),且不同机型的这个显示问题表现还不一样:

    • 红米 Note 8: Screenshot_2020-02-12-19-12-37-081_com AIIC App 可以看到,抬头处有一些蓝色的颜色块

    • 小米 Mix 2: Screenshot_2020-02-12-19-16-38-359_com AIIC App 可以看到,抬头处有一些下面 UI 的影子;此外在程序运行过程中,抬头处会出现闪屏的现象

    不知这是属于我的编码问题,还是属于兼容性问题?

    opened by carefree0910 4
  • 使用UIWidgets开发桌面应用的透明UI穿透问题

    使用UIWidgets开发桌面应用的透明UI穿透问题

    在开发桌面应用过程中,全屏透明UI中边缘为按钮、清单等Widgets,中间部分属于透明UI,是否可以将透明部分的点击事件等穿透传递下去来达到点击场景物体的目的,目前思路是在UIWidgetsPanel的事件处理函数中检测当前点击位置的像素颜色,低于阈值则将事件传递下去,但是目前在获取其texture转为texture2D后像素点的颜色始终为0XCDCDCDCD,能否提供一些帮助?

    enhancement 
    opened by liusujin 4
  • GestureDetector report onScaleUpdate with unexpected value in UIWidgetsEditorWindow

    GestureDetector report onScaleUpdate with unexpected value in UIWidgetsEditorWindow

    Expected Behaviour

    According to flutter/issues/13101, onScaleUpdate should report scale = 1.0 when there is only one pointer down on the screen, which also known as a pan or drag gesture.

    Current Behaviour

    In UIWidgetsPanel the GestureDetector works well. In UIWidgetsEditorWindow the GestureDetector reports a value that is not 1.0 when dragging around. (Unity 2018.4.0, macOS 10.14.5)

    Test Script

    ScrollView.cs

    using System;
    using System.Collections.Generic;
    using FinGameWorks.Scripts.Helpers;
    using Unity.UIWidgets.foundation;
    using Unity.UIWidgets.material;
    using Unity.UIWidgets.painting;
    using Unity.UIWidgets.ui;
    using Unity.UIWidgets.widgets;
    using UnityEngine;
    using Transform = Unity.UIWidgets.widgets.Transform;
    
    namespace FinGameWorks.Scripts.Views
    {
        public class ScrollView : StatefulWidget
        {
            public readonly Widget child;
            public float MinScale;
            public float MaxScale;
            public float ContentSizeWidth;
            public float ContentSizeHeight;
            
            public ScrollView(Widget child, float minScale = 0.5f, float maxScale = 3.0f, float contentSizeWidth = 2000, float contentSizeHeight = 2000, Key key = null) : base(key)
            {
                this.child = child;
                MinScale = minScale;
                MaxScale = maxScale;
                ContentSizeWidth = contentSizeWidth;
                ContentSizeHeight = contentSizeHeight;
            }
    
            public override State createState()
            {
                return new ScrollViewState();
            }
        }
    
        public class ScrollViewState : SingleTickerProviderStateMixin<ScrollView>
        {
            public Offset Offset = Offset.zero;
            public float Scale = 1;
            public Offset MoveVelocity = Offset.zero;
            public GlobalKey ContentViewContainerKey = GlobalKey.key();
    
            private float aimedScale = 1;
            private Offset aimedOffset = Offset.zero;
    //        private Offset scaleOrigin = Offset.zero;
            private Offset previousPointerPosition = Offset.zero;
            private TimeSpan previousTime = TimeSpan.Zero;
            private float previousScale = 1;
            
            public override void initState()
            {
                base.initState();
                WidgetsBinding.instance.scheduleFrameCallback(FrameCallback);
            }
    
            private void FrameCallback(TimeSpan dur)
            {
                setState(() =>
                {
    //                Offset moveDampSpeed = Offset.zero;
    //                Offset offsetDampSpeed = Offset.zero;
    //                float scaleDampSpeed = 0;
                    
    //                MoveVelocity = MoveVelocity.DampTo(Offset.zero, ref moveDampSpeed, 0.5f);
    //                aimedOffset += MoveVelocity / (1000.0f / (dur - previousTime).Milliseconds);
    //                Offset = Offset.DampTo(aimedOffset, ref offsetDampSpeed,0.15f);
    //                Scale = Mathf.SmoothDamp(Scale, aimedScale, ref scaleDampSpeed, 0.2f);
    //                Scale = Mathf.Max(widget.MinScale, Scale);
    //                Scale = Mathf.Min(widget.MaxScale, Scale);
    //                float scaleDiff = Scale - previousScale;
    //                aimedOffset -= (scaleOrigin - aimedOffset) * scaleDiff;
                    
    //                previousTime = dur;
    //                previousScale = Scale;
                });
                WidgetsBinding.instance.scheduleFrameCallback(FrameCallback);
            }
            
            public override Widget build(BuildContext context)
            {
                return new GestureDetector
                (
                    onScaleStart: details =>
                    {
                    },
                    onScaleUpdate: details =>
                    {
    //                    MoveVelocity = Offset.zero;
                        
                        float scaleDiff = previousScale * (details.scale - 1);
                        if (aimedScale >= widget.MaxScale && scaleDiff > 0)
                        {
                            scaleDiff = 0;
                        }
                        if (aimedScale <= widget.MinScale && scaleDiff < 0)
                        {
                            scaleDiff = 0;
                        }
                        aimedScale += scaleDiff;
                        aimedScale = Mathf.Max(widget.MinScale, aimedScale);
                        aimedScale = Mathf.Min(widget.MaxScale, aimedScale);
                        
                        Offset scaleOffsetDiff = (aimedOffset - previousPointerPosition) * (scaleDiff / aimedScale);
                        aimedOffset += scaleOffsetDiff;
                        previousScale = details.scale;
                        Debug.Log("scaleDiff = " + scaleDiff);
                    },
                    onScaleEnd: details =>
                    {
    //                    MoveVelocity = details.velocity.pixelsPerSecond;
                    },
                    child: new Listener
                    (
                        onPointerDown: evt =>
                        {
                            previousPointerPosition = evt.position;
                        }, 
                        onPointerMove: evt =>
                        {
                            aimedOffset += evt.delta;
                            previousPointerPosition = evt.position;
                        },
                        onPointerScroll: evt =>
                        {
                            float scaleDiff = evt.delta.dy / MediaQuery.of(context).size.height;
                            if (aimedScale >= widget.MaxScale && scaleDiff > 0)
                            {
                                scaleDiff = 0;
                            }
                            if (aimedScale <= widget.MinScale && scaleDiff < 0)
                            {
                                scaleDiff = 0;
                            }
                            aimedOffset += (aimedOffset - evt.position) * (scaleDiff / aimedScale); 
                            aimedScale += scaleDiff;
                            aimedScale = Mathf.Max(widget.MinScale, aimedScale);
                            aimedScale = Mathf.Min(widget.MaxScale, aimedScale);
                            previousScale = aimedScale;
                        },
                        child:new ClipRect
                        (
                            clipBehavior:Clip.hardEdge,
                            child:new Stack
                            (
                                children: new List<Widget>
                                {
                                    new Positioned
                                    (
                                        left: aimedOffset.dx,
                                        top: aimedOffset.dy,
                                        child: Transform.scale
                                        (
                                            scale: aimedScale,
                                            child: new Container(
                                                key:ContentViewContainerKey,
                                                width: widget.ContentSizeWidth,
                                                height: widget.ContentSizeHeight,
                                                child:widget.child
                                            ),
                                            alignment:Alignment.topLeft
                                        )
                                    )
                                }
                            )
                        )
                    )
                );
            }
        }
    }
    

    GridPointView.cs

    using System;
    using Unity.UIWidgets.foundation;
    using Unity.UIWidgets.material;
    using Unity.UIWidgets.ui;
    using Unity.UIWidgets.widgets;
    using UnityEngine;
    using Canvas = Unity.UIWidgets.ui.Canvas;
    using Color = Unity.UIWidgets.ui.Color;
    
    namespace FinGameWorks.Scripts.Views
    {
        public class GridPointViewPainter : AbstractCustomPainter
        {
            private readonly float radius = 2f;
            private readonly float spacing = 60.0f;
            private Color color = Color.white;
    
            public GridPointViewPainter(float radius = 2, float spacing = 60.0f, Color color = null, Listenable repaint = null) : base(repaint)
            {
                this.radius = radius;
                this.spacing = spacing;
                this.color = color == null ? Colors.white : color;
            }
    
            public override void paint(Canvas canvas, Size size)
            {
                Path path = new Path();
                for (int x = 1; x < size.width / spacing; x++)
                {
                    for (int y = 1; y < size.height / spacing; y++)
                    {
                        path.addCircle(x * spacing,y * spacing, radius);
                    }
                }
    
                Paint paint = new Paint
                {
                    strokeWidth = 0,
                    color = color,
                    strokeCap = StrokeCap.round,
                    strokeJoin = StrokeJoin.round,
                    style = PaintingStyle.fill
                };
                canvas.drawPath(path,paint);
                
            }
    
            public override bool shouldRepaint(CustomPainter oldDelegate)
            {
                return true;
            }
        }
    
        public class GridPointView : StatefulWidget
        {
            public Widget Child;
            public readonly float Radius;
            public readonly float Spacing;
            public readonly float Opacity;
            
            public GridPointView(float radius = 2, float spacing = 60.0f, float opacity = 0.1f, Widget child = null, Key key = null) : base(key)
            {
                Child = child;
                Radius = radius;
                Spacing = spacing;
                Opacity = opacity;
            }
    
            public override State createState()
            {
                return new GridPointViewState();
            }
        }
    
        public class GridPointViewState : State<GridPointView>
        {
            public override Widget build(BuildContext context)
            {
                return new CustomPaint
                (
                    painter: new GridPointViewPainter
                    (
                        widget.Radius,
                        widget.Spacing,
                        Theme.of(context).dividerColor.withOpacity(widget.Opacity)
                    ),
                    isComplex: true,
                    willChange: true,
                    child: widget.Child
                );
            }
        }
    }
    

    AppMainScreen.cs

    using System.Collections.Generic;
    using Unity.UIWidgets.foundation;
    using Unity.UIWidgets.material;
    using Unity.UIWidgets.widgets;
    using UnityEngine;
    
    namespace FinGameWorks.Scripts.Views
    {
        public class AppMainScreen : StatefulWidget
        {
            public override State createState()
            {
                return new AppMainScreenState();
            }
        }
    
        class AppMainScreenState : State<AppMainScreen>
        {
            public override Widget build(BuildContext context)
            {
                return new Scaffold
                (
                    body: new SafeArea
                    (
                        child: new ScrollView(child: new GridPointView(1.5f,
                                    35,
                                    0.2f))
                    )
                );
            }
        }
    }
    

    (Or we can transfer the whole project on WeChat)

    Usage

    Notice the output of Debug.Log("scaleDiff = " + scaleDiff);

    opened by JustinFincher 4
  • UI Canvas visible on Safari but not on Chrome using WebGL

    UI Canvas visible on Safari but not on Chrome using WebGL

    Environment:

    • Unity 2018.3.11f1
    • UIWidgets commit d76d75340e015215c58b2fa12c39f68ff1df25d9
    • Auto Graphics API

    Issue: When exported to WebGL, my project using UIWidgets won't display the UI on Chrome (showing default Skybox), but it works well on Safari (see images below). You can visit https://wizardly-goodall-109263.netlify.com/ for a test. The console in Chrome didn't throw any error when loading the scene. 🤔 image

    Attachment: https://www.dropbox.com/s/2ajywuu8ybbxxol/UIWidgets-Chrome-Issue-Sample.zip?dl=0

    opened by JustinFincher 4
  • 使用UIWidgets开发游戏UI的性能问题

    使用UIWidgets开发游戏UI的性能问题

    按照指南在现有游戏项目中加入示例时,游戏运行会变得非常卡顿。所以我不得不用以下代码来避免游戏卡顿: Window.onFrameRateSpeedUp = () => { }; Window.onFrameRateCoolDown = () => { }; 但是我不知道这样会不会产生其他影响,所以想问一下这是在游戏项目中使用UIWidgets必须设置的步骤吗?还是我有什么地方没有注意到而导致了这种卡顿?

    opened by RF103T 3
  • Inconsistent Stack widget performance

    Inconsistent Stack widget performance

    When I use the stack widget like in flutter, I can't dynamically modify the children property to change the z-order of the child widgets.

    The following code can achieve the effect in flutter, but it has no effect in UIWidgets.

    我像 flutter 中那样使用 Stack widget 时,发现我不能动态修改children属性来改变子widget的前后顺序。

    以下代码可以在flutter中实现效果,但在UIWidgets中没有效果。

    flutter

    class MyHomePage extends StatefulWidget {
      final String title;
      MyHomePage({Key? key, required this.title}) : super(key: key);
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      var children = <Widget>[
        Positioned(
            top: 100,
            left: 100,
            child: Container(height: 100, width: 100, color: Colors.blue)),
        Positioned(
            top: 120,
            left: 120,
            child: Container(height: 100, width: 100, color: Colors.red))
      ];
    
      void _incrementCounter() {
        setState(() {
          var temp = children[0];
          children[0] = children[1];
          children[1] = temp;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(child: Stack(children: children)),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
      }
    }
    

    C#

    class MainUI : StatefulWidget
    {
        public MainUI(Key key = null) : base(key) { }
    
        public override State createState()
        {
            return new MainUIState();
        }
    }
    
    class MainUIState: State<MainUI>
    {
        int counter = 0;
    
        public override Widget build(BuildContext context)
        {
            List<Widget> widgets = new List<Widget>()
            {
                new Positioned(
                top: 100,
                left: 100,
                child: new Container(height : 100, width : 100, color : Colors.blue)),
                new Positioned(
                top: 120,
                left: 120,
                child: new Container(height : 100, width : 100, color : Colors.red))
            };
    
            return new ConstrainedBox(
                constraints: BoxConstraints.expand(),
                child: new Stack(
                    children : new List<Widget>()
                    {
                        new Column(
                                children: new List<Widget>()
                                {
                                    new Expanded(
                                            child: new Row(
                                                crossAxisAlignment : CrossAxisAlignment.start,
                                                children : new List<Widget>()
                                                {
                                                    new RaisedButton(
                                                        onPressed: () =>
                                                        {
                                                            this.setState(() =>
                                                            {
                                                                Widget temp = widgets[0];
                                                                widgets[0] = widgets[1];
                                                                widgets[1] = temp;
                                                            });
                                                        },
                                                        child : new Text("交换")
                                                    )
                                                }
                                            )
                                        )
                                }
                            ),
                            new Stack(
                                children: widgets
                            )
                    }
                )
            );
        }
    }
    
    opened by RF103T 0
  • 输入文本框的内容和光标之间对齐有问题。

    输入文本框的内容和光标之间对齐有问题。

    在文本输入框中,若想使用文本居中对齐或者右对齐的时候,文本内容会和光标之间有偏移。

    复现问题: 1、创建一个文本输入框; 2、更改属性textAlign为非left; 3、输入字符内容;(这时候光标不会处于文本最后方) 4、长按输入文本框、全选。(这时候会发现显示的文本内容,和选中阴影不一致,严重偏移)

    希望大佬们尽快解决该问题,拜谢。!

    opened by HiWenHao 2
  • 包管理器导入UIwidgets方法(不是问题,只是记录一下方便其他人)

    包管理器导入UIwidgets方法(不是问题,只是记录一下方便其他人)

    本人2020.2.1f1版本:

    1. Edit ->Project Settings -> Package Manager -> Advanced Settings -> Enable Preview Packages 打勾(非必要,只是顺带介绍一下新版本包管理器的预览版开关)
    2. Window -> Package Manager, 点击左上角+号,选择第三个add package from git URL,输入com.unity.uiwidgets即可导入
    opened by gejin19951116 1
Releases(release_1.5.4_stable)
  • release_1.5.4_stable(Oct 22, 2019)

  • release_1.5.4(Sep 9, 2019)

    In this release we mainly focus on the optimization and stabilization of the framework. We also upgrade UIWidgets to version 1.5.4, mainly derived from flutter 1.5.4.

    For detailed descriptions please refer to our ChangeLog

    Source code(tar.gz)
    Source code(zip)
Owner
Unity Technologies
Unity Technologies
Easily build and deploy your Dart web app to GitHub pages

Run flutter build web or dart pub run build_runner build and put the output in another branch. An easy way to update gh-pages. Install $ dart pub glob

Kevin Moore 183 Dec 20, 2022
Telnyx flutter - A Flutter package for both android and iOS which helps developers with Telnyx API services

Telnyx Flutter A Flutter package for both android and iOS which helps developers

Kfir Matityahu 0 Jan 23, 2022
Embeddable unity game engine view for Flutter.

flutter_unity_widget Flutter unity 3D widget for embedding unity in flutter. Now you can make awesome gamified features of your app in Unity and get i

Rex Raphael 1.7k Jan 8, 2023
Cross-platform utilities for developers.

DevWidgets DevWidgets is a W.I.P Flutter application with several tools such as generators, formatters and converters for developers. Clicking here yo

Gustavo Mauricio de Barros 90 Dec 29, 2022
AI Library to create efficient Artificial Neural Networks. Computation uses SIMD (Single Instruction Multiple Data) to improve performance.

eneural_net eNeural.net / Dart is an AI Library for efficient Artificial Neural Networks. The library is portable (native, JS/Web, Flutter) and the co

null 21 Dec 29, 2022
Purpose of this project is to create extendable architecture of making platform aware Widgets which automatically select platform specific implementation

Old good factory Main obstacle in creating native experience on Flutter is the fact that you are asked to rebuild two layouts using platform specific

Swav Kulinski (Robotoaster) 101 Oct 14, 2022
DEVS: Developer Board and Jobs Listing | For Developers, By Developers

devs Setup Currently, this DEVS project is using the master channel of the Flutter SDK. TODO: Migrate to beta Clone the project git clone https://gith

Flutter Philippines Community 40 Apr 16, 2022
:bug: Flutter debug helper widget with common and custom actions

Debug Friend Flutter debug helper widget with common and custom actions This helps you reduce the development and testing time of new features Show so

Stanislav Ilin 43 Dec 7, 2022
A Dart Build Plugin that uploads debug symbols for Android, iOS/macOS and source maps for Web to Sentry via sentry-cli

Sentry Dart Plugin A Dart Build Plugin that uploads debug symbols for Android, iOS/macOS and source maps for Web to Sentry via sentry-cli. For doing i

Sentry 36 Jan 4, 2023
Write and debug tests easily, built on integration_test

flutter_convenient_test: Write and debug tests easily, built on integration_test Quick demo full_video.mov Have questions? Though used in production e

fzyzcjy 324 Dec 21, 2022
Android Debug Drawer for faster development

Android Debug Drawer Faster development with Debug Drawer Features DeviceModule - common information about your device BuildModule - app build informa

Mantas Palaima 1.2k Nov 21, 2022
Adds a side menu in all screens with debug information

Adds a side menu in all screens with debug information. You can decide which information to show and create new modules to include more information.

Sergi Martínez 27 Oct 7, 2022
Software analytics tool that helps developers analyse and improve software quality.

Dart Code Metrics Note: you can find the full documentation on the website Configuration | Rules | Metrics | Anti-patterns Dart Code Metrics is a stat

Dart Code Checker 745 Dec 26, 2022
This is an open source Tips & Tricks for Flutter, that helps flutter Developers write simple but powerful dart codes.

Showcasing-flutter - This is an open source Tips & Tricks for Flutter, that helps flutter Developers write simple but powerful dart codes.

Paul Edeme'kong - Flutter Fairy 1 Jan 4, 2022
This repo contains a collection of permission related Flutter plugins which can be used to request permissions to access device resources in a cross-platform way.

Flutter Permission Plugins Deprecation Notice This repository has been replaced by the Flutter permission_handler plugin and will not longer be mainta

Baseflow 51 Dec 13, 2021
Data Migrator - provide a universal translator for data by being portable, diverse, and efficient in migrating and converting data across discrete schemas

Data Migrator - provide a universal translator for data by being portable, diverse, and efficient in migrating and converting data across discrete schemas

Tanner Meade 77 Jan 2, 2023
CircularProfileAvatar is a Flutter package which allows developers to implement circular profile avatar

CircularProfileAvatar is a Flutter package which allows developers to implement circular profile avatar with border, overlay, initialsText and many other awesome features, which simplifies developers job. It is an alternative to Flutter's CircleAvatar Widget.

Muhammad Adil 85 Oct 5, 2022
Scouter is a package which was made following the goal to provide a NestJS-like experience to Dart Developers that want to develop Rest APIS

Scouter is a package which was made following the goal to provide a NestJS-like experience to Dart Developers that want to develop Rest APIS Features

Vinicius Amélio 3 Sep 12, 2022
An efficient and easy CA-Client interaction flutter project

Cloud Accounting An efficient and easy CA-Client interaction flutter project This is an application for a CA to interact with its clients. Clients can

null 1 Dec 18, 2022