提交 f01f9f8e authored 作者: Kevin's avatar Kevin

添加了自定义键盘

上级 86c950fa
## [0.1.7] - TODO:添加了自定义键盘
* TODO:添加了自定义键盘
* TODO:修改了下文档结构
## [0.1.6] - TODO:修改了Toast的位置计算方式 ## [0.1.6] - TODO:修改了Toast的位置计算方式
* TODO: 修改了Toast的位置计算方式 * TODO: 修改了Toast的位置计算方式
* TODO: 开放了Toast的位置设置 * TODO: 开放了Toast的位置设置
......
...@@ -7,177 +7,19 @@ Usage ...@@ -7,177 +7,19 @@ Usage
Add this to your package's pubspec.yaml file: Add this to your package's pubspec.yaml file:
``` yaml ``` yaml
dependencies: dependencies:
cool_ui: "^0.1.6" cool_ui: "^0.1.7"
``` ```
# 控件 # 控件
- [CupertinoPopoverButton](#CupertinoPopoverButton) - [CupertinoPopoverButton](documents/popover.md#CupertinoPopoverButton)
- [CupertinoPopoverMenuList](#CupertinoPopoverMenuList) - [CupertinoPopoverMenuList](documents/popover.md#CupertinoPopoverMenuList)
- [CupertinoPopoverMenuItem](#CupertinoPopoverMenuItem) - [CupertinoPopoverMenuItem](documents/popover.md#CupertinoPopoverMenuItem)
- [showWeuiToast](#showWeuiToast) - [showWeuiToast](documents/weui_toast.md#showWeuiToast)
- [showWeuiSuccessToast](#showWeuiSuccessToast) - [showWeuiSuccessToast](documents/weui_toast.md#showWeuiSuccessToast)
- [showWeuiLoadingToast](#showWeuiLoadingToast) - [showWeuiLoadingToast](documents/weui_toast.md#showWeuiLoadingToast)
## CupertinoPopoverButton # 自定义键盘
仿iOS的UIPopover效果的
用于弹窗的按钮 暂时未编写文档,具体请查看Demo与NumberKeyboard的实现
```dart \ No newline at end of file
CupertinoPopoverButton({
this.child,
this.popoverBuild,
this.popoverColor=Colors.white,
@required this.popoverWidth,
@required this.popoverHeight,
BoxConstraints popoverConstraints,
this.onTap,
this.transitionDuration=const Duration(milliseconds: 200),
this.radius=8.0});
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| child | <code>Widget</code> | | 按钮的内容 |
| popoverBuild | <code>WidgetBuilder</code> | | 生成弹出框的内容 |
| [popoverWidth] | <code>double</code> | | 弹出框的宽度 |
| [popoverHeight] | <code>double</code> | | 弹出框的高度 |
| [popoverConstraints] | <code>BoxConstraints</code> | maxHeight:123.0 maxWidth:150.0 | 弹出框的最大最小高宽|
| [onTap] | <code>BoolCallback</code> | | 按钮点击事件,返回true取消默认反应(不打开Popover) |
| [popoverColor] | <code>Color</code> | 白色 | 弹出框的背景颜色 |
| [transitionDuration] | <code>Duration</code> | 0.2s | 过度动画时间 |
| [radius] | <code>double</code> | 8.0 | 弹出框的圆角弧度 |
**Example**
```dart
CupertinoPopoverButton(
child: Container(
margin: EdgeInsets.all(20.0),
width: 80.0,
height: 40.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(5.0)),
boxShadow: [BoxShadow(color: Colors.black12,blurRadius: 5.0)]
),
child: Center(child:Text('左上角')),
),
popoverBuild:(BuildContext context){
return Container(
width: 100.0,
height: 100.0,
child: Text('左上角内容'),
)
});
```
<img width="38%" height="38%" src="./images/popover_demo.gif"/>
## CupertinoPopoverMenuList
Popover弹出的菜单样式列表,一般与[CupertinoPopoverMenuItem](#CupertinoPopoverMenuItem)一起用,会给两个Item加间隔线
```dart
CupertinoPopoverMenuList({this.children})
```
| Param | Type | Description |
| --- | --- | --- |
| children | <code>List<Widget></code> | 子元素,一般是CupertinoPopoverMenuItem |
## CupertinoPopoverMenuItem
单个菜单项
```dart
const CupertinoPopoverMenuItem({
this.leading,
this.child,
this.onTap,
this.isTapClosePopover=true
});
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [leading] | <code>Widget<Widget></code> | 菜单左边,一般放图标 |
| [child] | <code>Widget<Widget></code> | 菜单内容 |
| [onTap] | <code>BoolCallback</code> | | 按钮点击事件,返回true取消默认反应(不关闭Popover) |
| [isTapClosePopover] | <code>bool<Widget></code> | 是否点击关闭 |
#### 案例核心代码
```dart
CupertinoPopoverMenuList(
children: <Widget>[
CupertinoPopoverMenuItem(leading: Icon(Icons.add),child: Text("新增"),),
CupertinoPopoverMenuItem(leading: Icon(Icons.edit),child: Text("修改"),),
CupertinoPopoverMenuItem(leading: Icon(Icons.delete),child: Text("删除"),)
],
)
```
## showWeuiToast
仿Weui的Toast效果
```dart
VoidCallback showWeuiToast({
@required BuildContext context,
@required Widget message,
@required Widget icon,
Alignment alignment = const Alignment(0.0,-0.2),
RouteTransitionsBuilder transitionBuilder})
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [context] | <code>BuildContext<Widget></code> | | 上下文 |
| [message] | <code>Widget<Widget></code> | | 提示消息 |
| [alignment] | <code>Alignment<Widget></code>| 默认是居中偏上 | Toast的位置 |
| [icon] | <code>Widget<Widget></code> | | 图标 |
| [transitionBuilder] | <code>RouteTransitionsBuilder<Widget></code> | | 自定义过度动画 |
返回参数:VoidCallback,用于关闭Toast
<img width="38%" height="38%" src="./images/toast_demo.gif"/>
## showWeuiSuccessToast
仿Weui的SuccessToast效果
```dart
Future showWeuiSuccessToast({
@required BuildContext context,
@required Widget message=const Text("成功"),
Alignment alignment = const Alignment(0.0,-0.2),
RouteTransitionsBuilder transitionBuilder,
Duration closeDuration = const Duration(seconds: 3)
})
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [context] | <code>BuildContext<Widget></code> | | 上下文 |
| [transitionBuilder] | <code>RouteTransitionsBuilder<Widget></code> | | 自定义过度动画 |
| [alignment] | <code>Alignment<Widget></code>| 默认是居中偏上 | Toast的位置 |
| [message] | <code>Widget<Widget></code> | 成功| 提示消息 |
| [closeDuration] | <code>Duration<Widget></code> | 3s | 关闭时间 |
返回参数:Future dart 异步操作,代表Toast已关闭
## showWeuiLoadingToast
仿Weui的LoadingToast效果
```dart
VoidCallback showWeuiToast({
@required BuildContext context,
@required Widget message,
Alignment alignment = const Alignment(0.0,-0.2),
RouteTransitionsBuilder transitionBuilder
})
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [context] | <code>BuildContext<Widget></code> | | 上下文 |
| [message] | <code>Widget<Widget></code> | | 提示消息 |
| [alignment] | <code>Alignment<Widget></code>| 默认是居中偏上 | Toast的位置 |
| [transitionBuilder] | <code>RouteTransitionsBuilder<Widget></code> | | 自定义过度动画 |
返回参数:VoidCallback,用于关闭Toast
## CupertinoPopoverButton
仿iOS的UIPopover效果的
用于弹窗的按钮
```dart
CupertinoPopoverButton({
this.child,
this.popoverBuild,
this.popoverColor=Colors.white,
@required this.popoverWidth,
@required this.popoverHeight,
BoxConstraints popoverConstraints,
this.onTap,
this.transitionDuration=const Duration(milliseconds: 200),
this.radius=8.0});
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| child | <code>Widget</code> | | 按钮的内容 |
| popoverBuild | <code>WidgetBuilder</code> | | 生成弹出框的内容 |
| [popoverWidth] | <code>double</code> | | 弹出框的宽度 |
| [popoverHeight] | <code>double</code> | | 弹出框的高度 |
| [popoverConstraints] | <code>BoxConstraints</code> | maxHeight:123.0 maxWidth:150.0 | 弹出框的最大最小高宽|
| [onTap] | <code>BoolCallback</code> | | 按钮点击事件,返回true取消默认反应(不打开Popover) |
| [popoverColor] | <code>Color</code> | 白色 | 弹出框的背景颜色 |
| [transitionDuration] | <code>Duration</code> | 0.2s | 过度动画时间 |
| [radius] | <code>double</code> | 8.0 | 弹出框的圆角弧度 |
**Example**
```dart
CupertinoPopoverButton(
child: Container(
margin: EdgeInsets.all(20.0),
width: 80.0,
height: 40.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(5.0)),
boxShadow: [BoxShadow(color: Colors.black12,blurRadius: 5.0)]
),
child: Center(child:Text('左上角')),
),
popoverBuild:(BuildContext context){
return Container(
width: 100.0,
height: 100.0,
child: Text('左上角内容'),
)
});
```
<img width="38%" height="38%" src="./images/popover_demo.gif"/>
## CupertinoPopoverMenuList
Popover弹出的菜单样式列表,一般与[CupertinoPopoverMenuItem](#CupertinoPopoverMenuItem)一起用,会给两个Item加间隔线
```dart
CupertinoPopoverMenuList({this.children})
```
| Param | Type | Description |
| --- | --- | --- |
| children | <code>List<Widget></code> | 子元素,一般是CupertinoPopoverMenuItem |
## CupertinoPopoverMenuItem
单个菜单项
```dart
const CupertinoPopoverMenuItem({
this.leading,
this.child,
this.onTap,
this.isTapClosePopover=true
});
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [leading] | <code>Widget<Widget></code> | 菜单左边,一般放图标 |
| [child] | <code>Widget<Widget></code> | 菜单内容 |
| [onTap] | <code>BoolCallback</code> | | 按钮点击事件,返回true取消默认反应(不关闭Popover) |
| [isTapClosePopover] | <code>bool<Widget></code> | 是否点击关闭 |
#### 案例核心代码
```dart
CupertinoPopoverMenuList(
children: <Widget>[
CupertinoPopoverMenuItem(leading: Icon(Icons.add),child: Text("新增"),),
CupertinoPopoverMenuItem(leading: Icon(Icons.edit),child: Text("修改"),),
CupertinoPopoverMenuItem(leading: Icon(Icons.delete),child: Text("删除"),)
],
)
```
## showWeuiToast
仿Weui的Toast效果
```dart
VoidCallback showWeuiToast({
@required BuildContext context,
@required Widget message,
@required Widget icon,
Alignment alignment = const Alignment(0.0,-0.2),
RouteTransitionsBuilder transitionBuilder})
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [context] | <code>BuildContext<Widget></code> | | 上下文 |
| [message] | <code>Widget<Widget></code> | | 提示消息 |
| [alignment] | <code>Alignment<Widget></code>| 默认是居中偏上 | Toast的位置 |
| [icon] | <code>Widget<Widget></code> | | 图标 |
| [transitionBuilder] | <code>RouteTransitionsBuilder<Widget></code> | | 自定义过度动画 |
返回参数:VoidCallback,用于关闭Toast
<img width="38%" height="38%" src="./images/toast_demo.gif"/>
## showWeuiSuccessToast
仿Weui的SuccessToast效果
```dart
Future showWeuiSuccessToast({
@required BuildContext context,
@required Widget message=const Text("成功"),
Alignment alignment = const Alignment(0.0,-0.2),
RouteTransitionsBuilder transitionBuilder,
Duration closeDuration = const Duration(seconds: 3)
})
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [context] | <code>BuildContext<Widget></code> | | 上下文 |
| [transitionBuilder] | <code>RouteTransitionsBuilder<Widget></code> | | 自定义过度动画 |
| [alignment] | <code>Alignment<Widget></code>| 默认是居中偏上 | Toast的位置 |
| [message] | <code>Widget<Widget></code> | 成功| 提示消息 |
| [closeDuration] | <code>Duration<Widget></code> | 3s | 关闭时间 |
返回参数:Future dart 异步操作,代表Toast已关闭
## showWeuiLoadingToast
仿Weui的LoadingToast效果
```dart
VoidCallback showWeuiToast({
@required BuildContext context,
@required Widget message,
Alignment alignment = const Alignment(0.0,-0.2),
RouteTransitionsBuilder transitionBuilder
})
```
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [context] | <code>BuildContext<Widget></code> | | 上下文 |
| [message] | <code>Widget<Widget></code> | | 提示消息 |
| [alignment] | <code>Alignment<Widget></code>| 默认是居中偏上 | Toast的位置 |
| [transitionBuilder] | <code>RouteTransitionsBuilder<Widget></code> | | 自定义过度动画 |
返回参数:VoidCallback,用于关闭Toast
import 'package:cool_ui_example/cool_u_i_example_icons.dart'; import 'package:cool_ui_example/cool_u_i_example_icons.dart';
import 'package:cool_ui_example/pages/custom_keyboard.dart';
import 'package:cool_ui_example/pages/paint_event_demo.dart'; import 'package:cool_ui_example/pages/paint_event_demo.dart';
import 'package:cool_ui_example/pages/popover_demo.dart'; import 'package:cool_ui_example/pages/popover_demo.dart';
import 'package:cool_ui_example/pages/weui_toast_demo.dart'; import 'package:cool_ui_example/pages/weui_toast_demo.dart';
import 'package:cool_ui/cool_ui.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
void main() => runApp(MyApp()); void main(){
NumberKeyboard.register();
runApp(MyApp());
}
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
// This widget is the root of your application. // This widget is the root of your application.
...@@ -21,9 +27,9 @@ class MyApp extends StatelessWidget { ...@@ -21,9 +27,9 @@ class MyApp extends StatelessWidget {
// "hot reload" (press "r" in the console where you ran "flutter run", // "hot reload" (press "r" in the console where you ran "flutter run",
// or press Run > Flutter Hot Reload in IntelliJ). Notice that the // or press Run > Flutter Hot Reload in IntelliJ). Notice that the
// counter didn't reset back to zero; the application is not restarted. // counter didn't reset back to zero; the application is not restarted.
primarySwatch: Colors.blue primarySwatch: Colors.blue
), ),
home: MyHomePage(title: 'Flutter Demo Home Page'), home: MyHomePage(title: 'Flutter Demo Home Page')
); );
} }
} }
...@@ -69,34 +75,40 @@ class _MyHomePageState extends State<MyHomePage> { ...@@ -69,34 +75,40 @@ class _MyHomePageState extends State<MyHomePage> {
// fast, so that you can just rebuild anything that needs updating rather // fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets. // than having to individually change instances of widgets.
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by // 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. // the App.build method, and use it to set our appbar title.
title: Text(widget.title), title: Text(widget.title),
), ),
body: ListView( body: ListView(
children: <Widget>[ children: <Widget>[
ListTile( ListTile(
leading: Icon(CoolUIExampleIcon.popover), leading: Icon(CoolUIExampleIcon.popover),
title: Text("Popover"), title: Text("Popover"),
onTap: (){ onTap: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>PopoverDemo())); Navigator.of(context).push(MaterialPageRoute(builder: (context)=>PopoverDemo()));
}, },
), ),
ListTile( ListTile(
title: Text("PaintEvent"), title: Text("PaintEvent"),
onTap: (){ onTap: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>PaintEventDemo())); Navigator.of(context).push(MaterialPageRoute(builder: (context)=>PaintEventDemo()));
}, },
), ),
ListTile( ListTile(
title: Text("WeuiToastEvent"), title: Text("WeuiToastEvent"),
onTap: (){ onTap: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>WeuiToastDemo())); Navigator.of(context).push(MaterialPageRoute(builder: (context)=>WeuiToastDemo()));
}, },
) ),
], ListTile(
) title: Text("CustomKeyboardEvent"),
onTap: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>CustomKeyboardDemo()));
},
)
],
)
); );
} }
} }
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cool_ui/cool_ui.dart';
class CustomKeyboardDemo extends StatefulWidget{
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return CustomKeyboardDemoState();
}
}
class CustomKeyboardDemoState extends State<CustomKeyboardDemo>{
@override
Widget build(BuildContext context) {
// TODO: implement build
return KeyboardMediaQuery(
child: Builder(builder: (ctx) {
CoolKeyboard.init(ctx);
return Scaffold(
appBar: AppBar(
title: Text("Custom Keyboard Demo"),
),
body: ListView(
children: <Widget>[
TextField(
keyboardType: TextInputType.text,
),
Container(
height: 300.0,
),
TextField(
decoration: InputDecoration(labelText: '演示键盘弹出后滚动'),
keyboardType: NumberKeyboard.inputType,
)
],
)
);
})
);
}
}
\ No newline at end of file
library cool_ui; library cool_ui;
import 'dart:async';
import 'dart:ui' as ui;
import 'dart:core';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flustars/flustars.dart'; import 'package:flustars/flustars.dart';
import 'dart:async';
part 'icons/cool_ui_icons.dart'; part 'icons/cool_ui_icons.dart';
...@@ -12,3 +18,8 @@ part 'widgets/popover/cupertino_popover_menu_item.dart'; ...@@ -12,3 +18,8 @@ part 'widgets/popover/cupertino_popover_menu_item.dart';
part 'widgets/utils/paint_event.dart'; part 'widgets/utils/paint_event.dart';
part 'dialogs/weui_toast.dart'; part 'dialogs/weui_toast.dart';
part 'keyboards/keyboard_manager.dart';
part 'keyboards/number_keyboard.dart';
part 'keyboards/keyboard_controller.dart';
part 'keyboards/keyboard_media_query.dart';
\ No newline at end of file
part of cool_ui;
class KeyboardController extends ValueNotifier<TextEditingValue>{
final InputClient client;
KeyboardController({TextEditingValue value,this.client})
: super(value == null ? TextEditingValue.empty : value);
/// The current string the user is editing.
String get text => value.text;
/// Setting this will notify all the listeners of this [TextEditingController]
/// that they need to update (it calls [notifyListeners]). For this reason,
/// this value should only be set between frames, e.g. in response to user
/// actions, not during the build, layout, or paint phases.
set text(String newText) {
value = value.copyWith(text: newText,
selection: const TextSelection.collapsed(offset: -1),
composing: TextRange.empty);
}
/// The currently selected [text].
///
/// If the selection is collapsed, then this property gives the offset of the
/// cursor within the text.
TextSelection get selection => value.selection;
/// Setting this will notify all the listeners of this [TextEditingController]
/// that they need to update (it calls [notifyListeners]). For this reason,
/// this value should only be set between frames, e.g. in response to user
/// actions, not during the build, layout, or paint phases.
set selection(TextSelection newSelection) {
if (newSelection.start > text.length || newSelection.end > text.length)
throw FlutterError('invalid text selection: $newSelection');
value = value.copyWith(selection: newSelection, composing: TextRange.empty);
}
/// Set the [value] to empty.
///
/// After calling this function, [text] will be the empty string and the
/// selection will be invalid.
///
/// Calling this will notify all the listeners of this [TextEditingController]
/// that they need to update (it calls [notifyListeners]). For this reason,
/// this method should only be called between frames, e.g. in response to user
/// actions, not during the build, layout, or paint phases.
void clear() {
value = TextEditingValue.empty;
}
/// Set the composing region to an empty range.
///
/// The composing region is the range of text that is still being composed.
/// Calling this function indicates that the user is done composing that
/// region.
///
/// Calling this will notify all the listeners of this [TextEditingController]
/// that they need to update (it calls [notifyListeners]). For this reason,
/// this method should only be called between frames, e.g. in response to user
/// actions, not during the build, layout, or paint phases.
clearComposing() {
value = value.copyWith(composing: TextRange.empty);
}
deleteOne(){
if(selection.baseOffset == 0)
return;
String newText = '';
if(selection.baseOffset != selection.extentOffset)
{
newText = selection.textBefore(text) + selection.textAfter(text);
value = TextEditingValue(
text: newText,
selection: selection.copyWith(
baseOffset:selection.baseOffset,
extentOffset: selection.baseOffset)
);
}else{
newText = text.substring(0,selection.baseOffset - 1) + selection.textAfter(text);
value = TextEditingValue(
text: newText,
selection: selection.copyWith(
baseOffset:selection.baseOffset - 1,
extentOffset: selection.baseOffset - 1)
);
}
}
/// 在光标位置添加文字,一般用于键盘输入
addText(String insertText){
String newText = selection.textBefore(text) + insertText + selection.textAfter(text);
value = TextEditingValue(
text: newText,
selection: selection.copyWith(
baseOffset:selection.baseOffset + insertText.length,
extentOffset: selection.baseOffset + insertText.length)
);
}
/// 完成
doneAction(){
CoolKeyboard.sendPerformAction(TextInputAction.done);
}
}
\ No newline at end of file
part of cool_ui;
typedef GetKeyboardHeight = double Function(BuildContext context);
typedef KeyboardBuilder = Widget Function(BuildContext context,KeyboardController controller);
class CoolKeyboard {
static JSONMethodCodec _codec = const JSONMethodCodec();
static KeyboardConfig _currentKeyboard;
static Map<CKTextInputType,KeyboardConfig> _keyboards = {};
static BuildContext _context;
static OverlayEntry _keyboardEntry;
static KeyboardController _keyboardController;
static GlobalKey<KeyboardPageState> _pageKey;
static bool isInterceptor = false;
static double get keyboardHeight =>_keyboardHeight;
static double _keyboardHeight;
static init(BuildContext context){
_context = context;
interceptorInput();
}
static interceptorInput(){
if(isInterceptor)
return;
isInterceptor = true;
BinaryMessages.setMockMessageHandler("flutter/textinput", (ByteData data) async{
var methodCall = _codec.decodeMethodCall(data);
switch(methodCall.method){
case 'TextInput.show':
if(_currentKeyboard != null){
openKeyboard();
return _codec.encodeSuccessEnvelope(null);
}else{
return await _sendPlatformMessage("flutter/textinput", data);
}
break;
case 'TextInput.hide':
if(_currentKeyboard != null){
hideKeyboard();
return _codec.encodeSuccessEnvelope(null);
}else{
return await _sendPlatformMessage("flutter/textinput", data);
}
break;
case 'TextInput.setEditingState':
var editingState = TextEditingValue.fromJSON(methodCall.arguments);
if(editingState != null && _keyboardController != null){
_keyboardController.value = editingState;
return _codec.encodeSuccessEnvelope(null);
}
break;
case 'TextInput.clearClient':
hideKeyboard(animation:true);
clearKeyboard();
break;
case 'TextInput.setClient':
var setInputType = methodCall.arguments[1]['inputType'];
InputClient client;
_keyboards.forEach((inputType,keyboardConfig){
if(inputType.name == setInputType['name']){
client = InputClient.fromJSON(methodCall.arguments);
clearKeyboard();
_currentKeyboard = keyboardConfig;
_keyboardController = KeyboardController(client:client)..addListener((){
var callbackMethodCall = MethodCall("TextInputClient.updateEditingState",[_keyboardController.client.connectionId,_keyboardController.value.toJSON()]);
BinaryMessages.handlePlatformMessage("flutter/textinput", _codec.encodeMethodCall(callbackMethodCall), (data){});
});
}
});
if(client != null){
await _sendPlatformMessage("flutter/textinput", _codec.encodeMethodCall(MethodCall('TextInput.hide')));
return _codec.encodeSuccessEnvelope(null);
}else{
hideKeyboard(animation:false);
clearKeyboard();
}
break;
}
ByteData response = await _sendPlatformMessage("flutter/textinput", data);
return response;
});
}
static Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
final Completer<ByteData> completer = Completer<ByteData>();
ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: 'during a platform message response callback',
));
}
});
return completer.future;
}
static addKeyboard(CKTextInputType inputType,KeyboardConfig config){
_keyboards[inputType] = config;
}
static openKeyboard(){
if(_keyboardEntry != null)
return;
_pageKey = GlobalKey<KeyboardPageState>();
_keyboardHeight = _currentKeyboard.getHeight(_context);
_context.ancestorStateOfType(const TypeMatcher<KeyboardMediaQueryState>()).setState((){});
var tempKey = _pageKey;
_keyboardEntry = OverlayEntry(builder: (ctx) {
if(_currentKeyboard != null && _keyboardHeight != null)
{
return KeyboardPage(
key: tempKey,
child: Builder(builder: (ctx){
return _currentKeyboard.builder(ctx,_keyboardController);
}),
height:_keyboardHeight
);
}else{
return Container();
}
});
Overlay.of(_context).insert(_keyboardEntry);
}
static hideKeyboard({bool animation=true}){
if(_keyboardEntry != null) {
_keyboardHeight = null;
_pageKey.currentState.animationController.addStatusListener((status) {
if (status == AnimationStatus.dismissed ||
status == AnimationStatus.completed) {
if (_keyboardEntry != null) {
_keyboardEntry.remove();
_keyboardEntry = null;
}
}
});
if (animation)
{
_pageKey.currentState.exitKeyboard();
}
else{
_keyboardEntry.remove();
_keyboardEntry = null;
}
}
_pageKey = null;
_context.ancestorStateOfType(const TypeMatcher<KeyboardMediaQueryState>()).setState((){});
}
static clearKeyboard(){
_currentKeyboard = null;
if(_keyboardController != null){
_keyboardController.dispose();
_keyboardController = null;
}
}
static sendPerformAction(TextInputAction action){
var callbackMethodCall = MethodCall("TextInputClient.performAction",
[
_keyboardController.client.connectionId,
action.toString()
]);
BinaryMessages.handlePlatformMessage(
"flutter/textinput", _codec.encodeMethodCall(callbackMethodCall), (
data) {});
}
}
class KeyboardConfig{
final KeyboardBuilder builder;
final GetKeyboardHeight getHeight;
const KeyboardConfig({this.builder,this.getHeight});
}
class InputClient{
final int connectionId;
final TextInputConfiguration configuration;
const InputClient({this.connectionId,this.configuration});
factory InputClient.fromJSON(List<dynamic> encoded) {
return InputClient(connectionId: encoded[0],configuration: TextInputConfiguration(
inputType:CKTextInputType.fromJSON(encoded[1]['inputType']),
obscureText:encoded[1]['obscureText'],
autocorrect:encoded[1]['autocorrect'],
actionLabel:encoded[1]['actionLabel'],
inputAction:_toTextInputAction(encoded[1]['inputAction']),
textCapitalization:_toTextCapitalization(encoded[1]['textCapitalization']),
keyboardAppearance:_toBrightness(encoded[1]['keyboardAppearance'])
));
}
static TextInputAction _toTextInputAction(String action) {
switch (action) {
case 'TextInputAction.none':
return TextInputAction.none;
case 'TextInputAction.unspecified':
return TextInputAction.unspecified;
case 'TextInputAction.go':
return TextInputAction.go;
case 'TextInputAction.search':
return TextInputAction.search;
case 'TextInputAction.send':
return TextInputAction.send;
case 'TextInputAction.next':
return TextInputAction.next;
case 'TextInputAction.previuos':
return TextInputAction.previous;
case 'TextInputAction.continue_action':
return TextInputAction.continueAction;
case 'TextInputAction.join':
return TextInputAction.join;
case 'TextInputAction.route':
return TextInputAction.route;
case 'TextInputAction.emergencyCall':
return TextInputAction.emergencyCall;
case 'TextInputAction.done':
return TextInputAction.done;
case 'TextInputAction.newline':
return TextInputAction.newline;
}
throw FlutterError('Unknown text input action: $action');
}
static TextCapitalization _toTextCapitalization(String capitalization){
switch(capitalization){
case 'TextCapitalization.none':
return TextCapitalization.none;
case 'TextCapitalization.characters':
return TextCapitalization.characters;
case 'TextCapitalization.sentences':
return TextCapitalization.sentences;
case 'TextCapitalization.words':
return TextCapitalization.words;
}
throw FlutterError('Unknown text capitalization: $capitalization');
}
static Brightness _toBrightness(String brightness){
switch(brightness){
case 'Brightness.dark':
return Brightness.dark;
case 'Brightness.light':
return Brightness.light;
}
throw FlutterError('Unknown Brightness: $brightness');
}
}
class CKTextInputType extends TextInputType{
final String name;
const CKTextInputType({this.name,bool signed,bool decimal}) : super.numberWithOptions(signed:signed,decimal:decimal);
@override
Map<String, dynamic> toJson() {
return <String, dynamic>{
'name': name,
'signed': signed,
'decimal': decimal,
};
}
factory CKTextInputType.fromJSON(Map<String,dynamic> encoded) {
return CKTextInputType(
name: encoded['name'],
signed: encoded['signed'],
decimal: encoded['decimal']
);
}
}
class KeyboardPage extends StatefulWidget{
final Widget child;
final double height;
const KeyboardPage({this.child,this.height,Key key}):super(key:key);
@override
State<StatefulWidget> createState() =>KeyboardPageState();
}
class KeyboardPageState extends State<KeyboardPage> with SingleTickerProviderStateMixin{
AnimationController animationController;
Animation<double> doubleAnimation;
double bottom;
@override
void initState() {
// TODO: implement initState
super.initState();
animationController = new AnimationController(duration: new Duration(milliseconds: 100),vsync: this)
..addListener(()=>setState((){}));
doubleAnimation =
new Tween(begin: 0.0, end: widget.height).animate(animationController)..addListener(()=>setState((){}));
animationController.forward(from:0.0);
}
@override
Widget build(BuildContext context) {
return Positioned(
child: IntrinsicHeight(
child: widget.child
),
bottom: (widget.height - doubleAnimation.value) * -1
);
}
@override
void dispose() {
super.dispose();
animationController.dispose();
}
exitKeyboard(){
animationController.reverse();
}
}
part of cool_ui;
class KeyboardMediaQuery extends StatefulWidget{
final Widget child;
KeyboardMediaQuery({this.child})
: assert(child != null);
@override
State<StatefulWidget> createState() =>KeyboardMediaQueryState();
}
class KeyboardMediaQueryState extends State<KeyboardMediaQuery >{
@override
Widget build(BuildContext context) {
// TODO: implement build
var data = MediaQuery.of(context);
print('KeyboardMediaQuery${CoolKeyboard.keyboardHeight}');
// TODO: implement build
return MediaQuery(
child: widget.child,
data:data.copyWith(viewInsets: data.viewInsets.copyWith(bottom: CoolKeyboard.keyboardHeight))
);;
}
}
\ No newline at end of file
part of cool_ui;
class NumberKeyboard extends StatelessWidget{
static const CKTextInputType inputType = const CKTextInputType(name:'CKNumberKeyboard');
static double getHeight(BuildContext ctx){
MediaQueryData mediaQuery = MediaQuery.of(ctx);
return mediaQuery.size.width / 3 / 2 * 4;
}
final KeyboardController controller ;
const NumberKeyboard({this.controller});
static register(){
CoolKeyboard.addKeyboard(NumberKeyboard.inputType,KeyboardConfig(builder: (context,controller){
return NumberKeyboard(controller: controller);
},getHeight: NumberKeyboard.getHeight));
}
@override
Widget build(BuildContext context) {
MediaQueryData mediaQuery = MediaQuery.of(context);
return Material(
child: DefaultTextStyle(style: TextStyle(fontWeight: FontWeight.w500,color: Colors.black,fontSize: 23.0), child: Container(
height:getHeight(context),
width: mediaQuery.size.width,
decoration: BoxDecoration(
color: Color(0xffafafaf),
),
child: GridView.count(
childAspectRatio: 2/1,
mainAxisSpacing:0.5,
crossAxisSpacing:0.5,
padding: EdgeInsets.all(0.0),
crossAxisCount: 3,
children: <Widget>[
buildButton('1'),
buildButton('2'),
buildButton('3'),
buildButton('4'),
buildButton('5'),
buildButton('6'),
buildButton('7'),
buildButton('8'),
buildButton('9'),
Container(
color: Color(0xFFd3d6dd),
child: GestureDetector(
behavior: HitTestBehavior.translucent,
child: Center(child: Icon(Icons.expand_more),),
onTap: (){
controller.doneAction();
},
),
),
buildButton('0'),
Container(
color: Color(0xFFd3d6dd),
child: GestureDetector(
behavior: HitTestBehavior.translucent,
child: Center(child: Text('X'),),
onTap: (){
controller.deleteOne();
},
),
),
]),
)),
);
}
Widget buildButton(String title,{String value}){
if(value == null){
value = title;
}
return Container(
color: Colors.white,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
child: Center(child: Text(title),),
onTap: (){
controller.addText(value);
},
),
);
}
}
# Generated by pub # Generated by pub
# See https://www.dartlang.org/tools/pub/glossary#lockfile # See https://www.dartlang.org/tools/pub/glossary#lockfile
packages: packages:
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.32.4"
args:
dependency: transitive
description:
name: args
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.5.0"
async: async:
dependency: transitive dependency: transitive
description: description:
...@@ -43,27 +29,13 @@ packages: ...@@ -43,27 +29,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.14.11" version: "1.14.11"
convert: cupertino_icons:
dependency: transitive dependency: "direct main"
description:
name: convert
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.2"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.6"
csslib:
dependency: transitive
description: description:
name: csslib name: cupertino_icons
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.14.5" version: "0.1.2"
flustars: flustars:
dependency: "direct main" dependency: "direct main"
description: description:
...@@ -81,83 +53,6 @@ packages: ...@@ -81,83 +53,6 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
front_end:
dependency: transitive
description:
name: front_end
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.4"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.7"
html:
dependency: transitive
description:
name: html
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.13.3+3"
http:
dependency: transitive
description:
name: http
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.11.3+17"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.5"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.3"
io:
dependency: transitive
description:
name: io
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.3"
js:
dependency: transitive
description:
name: js
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.6.1+1"
json_rpc_2:
dependency: transitive
description:
name: json_rpc_2
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.9"
kernel:
dependency: transitive
description:
name: kernel
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.4"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.11.3+2"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
...@@ -172,41 +67,6 @@ packages: ...@@ -172,41 +67,6 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.6" version: "1.1.6"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.6+2"
multi_server_socket:
dependency: transitive
description:
name: multi_server_socket
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.2"
node_preamble:
dependency: transitive
description:
name: node_preamble
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.4"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.5"
package_resolver:
dependency: transitive
description:
name: package_resolver
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.4"
path: path:
dependency: transitive dependency: transitive
description: description:
...@@ -214,34 +74,13 @@ packages: ...@@ -214,34 +74,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.6.2" version: "1.6.2"
plugin:
dependency: transitive
description:
name: plugin
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.0+3"
pool:
dependency: transitive
description:
name: pool
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.6"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.2"
quiver: quiver:
dependency: transitive dependency: transitive
description: description:
name: quiver name: quiver
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.0+1" version: "2.0.1"
shared_preferences: shared_preferences:
dependency: transitive dependency: transitive
description: description:
...@@ -249,53 +88,11 @@ packages: ...@@ -249,53 +88,11 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.4.3" version: "0.4.3"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.7.3+3"
shelf_packages_handler:
dependency: transitive
description:
name: shelf_packages_handler
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.4"
shelf_static:
dependency: transitive
description:
name: shelf_static
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.8"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.2+4"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.99"
source_map_stack_trace:
dependency: transitive
description:
name: source_map_stack_trace
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.5"
source_maps:
dependency: transitive
description:
name: source_maps
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.10.7"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
...@@ -338,13 +135,13 @@ packages: ...@@ -338,13 +135,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
test: test_api:
dependency: transitive dependency: transitive
description: description:
name: test name: test_api
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.0" version: "0.2.1"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
...@@ -352,13 +149,6 @@ packages: ...@@ -352,13 +149,6 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.6" version: "1.1.6"
utf:
dependency: transitive
description:
name: utf
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.0+5"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
...@@ -366,34 +156,6 @@ packages: ...@@ -366,34 +156,6 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.8" version: "2.0.8"
vm_service_client:
dependency: transitive
description:
name: vm_service_client
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.6"
watcher:
dependency: transitive
description:
name: watcher
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.7+10"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.9"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.15"
sdks: sdks:
dart: ">=2.0.0 <3.0.0" dart: ">=2.0.0 <3.0.0"
flutter: ">=0.1.4 <2.0.0" flutter: ">=0.1.4 <2.0.0"
name: cool_ui name: cool_ui
description: 用flutter实现一些我认为好看的UI控件,目前暂时只有Popover,Weui,不过有什么觉得好看的可以提Issue description: 用flutter实现一些我认为好看的UI控件,目前暂时只有Popover,Weui,不过有什么觉得好看的可以提Issue
version: 0.1.6 version: 0.1.7
author: Kevin <liangkaikevin@gmail.com> author: Kevin <liangkaikevin@gmail.com>
homepage: https://github.com/Im-Kevin/cool_ui homepage: https://github.com/Im-Kevin/cool_ui
...@@ -11,7 +11,6 @@ dependencies: ...@@ -11,7 +11,6 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flustars: 0.1.3 flustars: 0.1.3
dev_dependencies: dev_dependencies:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论