Flutter
鐨勪笁鏂瑰伐鍏锋湁涓ょ锛屼竴绉嶆槸鎻掍欢
锛圥lugin锛夛紝涓€绉嶆槸鍖?/code>锛圥ackage锛夈€傝繖涓ょ宸埆鍦ㄤ簬
浠ュ強Plugin
涓嶄粎鍖呭惈Dart
浠g爜锛岃繕鍖呭惈浜?code>iOS瀹夊崜
鐨勫師鐢熶唬鐮侊紝姣斿甯歌鐨?code>image_picker锛涜€?code>Package浠呬粎鏄?code>Dart浠g爜搴撱€?/p>
package寮€鍙?/h2>
涓嬮潰鎴戜滑寮€鍙戜竴涓?code>鏀寔绌哄畨鍏?/code>鐨勫簱锛屽氨鐢ㄤ箣鍓嶇殑wechat_demo
宸ョ▼涓?code>閫氳褰曢〉闈?/code>鍙充晶鐨?code>IndexBar杩涜缁冧範
- 鏂板缓
Package
宸ョ▼logic_package_demo
锛屾敞鎰?code>Project type閫夋嫨Package
- 鏌ョ湅
宸ョ▼鐩綍
锛屽彂鐜板苟涓嶅寘鍚?code>iOS銆?code>瀹夊崜鐩綍
-
绌哄畨鍏ㄧ増鏈?/code>鐩稿叧閰嶇疆渚濈劧鍦?code>pubspec.yaml
鏂囦欢涓?/li> -
Package
宸ョ▼寮曠敤璧勬簮鍥剧墖锛?code>New -> Directory鏂板缓images
鐩綍锛屾妸鍥剧墖璧勬簮鏀惧叆鐩綍
-
pubspec.yaml
鏂囦欢杩涜閰嶇疆锛屽紩鍏ュ浘鐗囪祫婧?/li>
- 鍗曞厓娴嬭瘯
test
鐩綍涓嬬殑鎶ラ敊鍏堝垹鎺?/li>
-
logic_package_demo.dart
鏂囦欢鍐呭
library logic_package_demo;
import 'package:flutter/material.dart';
class IndexBar extends StatefulWidget {
// 瀵瑰鎻愪緵鍥炶皟锛屽憡璇塮riends_page褰撳墠閫変腑鐨勬槸鏍囪瘑
final void Function(String str) indexBarCallBack;
const IndexBar({required this.indexBarCallBack, Keykey}) : super(key: key);
@override
State<StatefulWidget> createState() => _IndexBarState();
}
// 鑾峰彇閫変腑鐨刬tem鐨勫瓧绗?!
// context灏辨槸widget涓殑Element
int getIndex(BuildContext context, Offset globalPosition) {
// 鑾峰彇褰撳墠灏忛儴浠剁殑鐩掑瓙锛岀被鍨嬪己杞琑enderBox
RenderBox box = context.findRenderObject() as RenderBox;
// 鑾峰彇y鍊?globalToLocald褰撳墠浣嶇疆璺濈閮ㄤ欢鍘熺偣(宸︿笂瑙?鐨勪綅缃?
double y = box.globalToLocal(globalPosition).dy;
// 绠楀嚭瀛楃楂樺害
var itemHeight = screenHeigth(context) / 2 / INDEX_WORDS.length;
// 绠楀嚭绗嚑涓猧tem, clamp绾︽潫index鑼冨洿鍊?
int index = (y ~/ itemHeight).clamp(0, INDEX_WORDS.length - 1);
return index;
}
class _IndexBarState extends State<IndexBar> {
// 绱㈠紩鏉¢€変腑 鑳屾櫙鑹蹭笌鏂囧瓧棰滆壊
Color _bkColor = Color.fromRGBO(1, 1, 1, 0.0);
Color _textColor = Colors.black;
// 娣诲姞鍥剧墖鎸囩ず鍣╕鍊硷紝鏄剧ず绱㈠紩鏍囪瘑锛屾槸鍚︽樉绀虹瓑灞炴€?
double _indicatorY = 0.0;
String _indicatorText = 'A';
bool _indicatorHidden = true;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
// 涓庣晫闈㈢浉鍏崇殑鏁版嵁瑕佹斁鍏uild涓?
final List<Widget> words = [];
for (int i = 0; i < INDEX_WORDS.length; i++) {
words.add(Expanded(
child: Text(
INDEX_WORDS[i],
style: TextStyle(fontSize: 10, color: _textColor),
)));
}
// TODO: implement build
return Positioned(
right: 0.0,
top: screenHeigth(context) / 8,
height: screenHeigth(context) / 2,
width: 120,
// 娣诲姞鎵嬪娍
child: Row(
children: [
Container(
alignment: Alignment(0, _indicatorY),
width: 100,
// color: Colors.red,
child: _indicatorHidden
null
: Stack(
// 璁╂皵娉″眳涓?
alignment: Alignment(-0.2, 0),
children: [
Image(
image: AssetImage('images/姘旀场.png'),
width: 60,
),
Text(
_indicatorText,
style: TextStyle(fontSize: 35, color: Colors.white),
)
],
),
), //鎸囩ず鍣?
GestureDetector(
// 鎷栨嫿鎵嬪娍
onVerticalDragUpdate: (DragUpdateDetails details) {
// String str = getIndex(context, details.globalPosition);
// print('閫変腑鐨勬槸$str');
int index = getIndex(context, details.globalPosition);
widget.indexBarCallBack(INDEX_WORDS[index]);
setState(() {
_indicatorY = 2.2 / INDEX_WORDS.length * index - 1.1;
_indicatorText = INDEX_WORDS[index];
_indicatorHidden = false;
});
},
// 鐐瑰嚮绱㈠紩
onVerticalDragDown: (DragDownDetails details) {
int index = getIndex(context, details.globalPosition);
widget.indexBarCallBack(INDEX_WORDS[index]);
setState(() {
_indicatorY = 2.2 / INDEX_WORDS.length * index - 1.1;
_indicatorText = INDEX_WORDS[index];
_indicatorHidden = false;
_bkColor = Color.fromRGBO(1, 1, 1, 0.5);
_textColor = Colors.white;
});
},
// 鐐瑰嚮缁撴潫,棰滆壊鍊艰繕鍘?
onVerticalDragEnd: (DragEndDetails details) {
setState(() {
_indicatorHidden = true;
_bkColor = Color.fromRGBO(1, 1, 1, 0.0);
_textColor = Colors.black;
});
},
child: Container(
// 璁剧疆瀹藉害锛岃鍙充晶绱㈠紩灞呬腑
width: 20,
color: _bkColor,
child: Column(
children: words,
),
),
), //绱㈠紩鏉?
],
),
);
}
}
//涓婚鑹?
//const淇グ鐨勫父閲忥紝鍚嶇О棣栧瓧姣嶅彲浠ユ槸澶у啓
const Color WeChatThemeColor = Color.fromRGBO(220, 220, 220, 1.0);
//灞忓箷瀹藉害
//灞忓箷瀹藉害鏄€氳繃璁$畻鏉ヨ幏鍙栵紝涓嶈兘瀹氫箟鎴愬父閲忥紱棣栧瓧姣嶉渶瑕佸皬鍐?
double screenWidth(BuildContext context) => MediaQuery.of(context).size.width;
double screenHeigth(BuildContext context) => MediaQuery.of(context).size.height;
const INDEX_WORDS = [
'馃攳',
'鈽?,
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
];
-
Package
鍖呭彂甯冨墠閰嶇疆
-
Package
鍖呰繘琛屽彂甯?/li>
// 杩涘叆logic_package_demo宸ョ▼鐩綍
$ cd /Users/wn/Desktop/logic_package_demo
// 妫€鏌ackage鍖?
$ flutter packages pub publish --dry-run
姣斿pubspec.yaml
鏂囦欢涓殑homepage
娌℃湁閰嶇疆锛屾鏌ョ殑鏃跺€欏氨浼氭姤閿欍€?/p>
// Package鍖呰繘琛屽彂甯?
$ flutter packages pub publish
娉ㄦ剰锛?/strong>鐩墠鍙戝竷鎻掍欢鍜屽寘閮介渶瑕?code>Google璐﹀彿锛屽悓鏃堕渶瑕佺炕澧欍€?/p>
褰撳嚭鐜颁笅闈㈡彁绀猴紝闇€瑕佷綘浣跨敤娴忚鍣ㄨ闂彁绀轰腑鐨勯摼鎺ワ紝鐢ㄤ綘鐨?code>Google璐﹀彿鎺堟潈銆?/p>
鏈夋椂灏辩畻鏄炕澧欎篃骞朵笉鑳借В鍐抽棶棰橈紝鍥犱负鎴戜滑杩橀厤缃簡鐩稿叧鐨勯暅鍍忋€?code>Flutter瀹樻柟灏卞缓璁繃闀滃儚鐨勯厤缃紝鎵€浠ユ垜浠湪鍙戝竷鎻掍欢鎴栬€呭寘鐨勬椂鍊欙紝灏变細鍥犱负闀滃儚鍑虹幇涓嬮潰閿欒锛?/p>
瑙e喅鍔炴硶锛?code>鎸囧畾鏈嶅姟鍣ㄥ彂甯?/code> 鍙戝竷鍖呯殑涓€涓増鏉冮棶棰橈紝杩欎釜璇佷功闇€瑕佸湪 鎶婅瘉涔︽枃浠跺唴瀹瑰鍒跺埌 绛夊緟 杩欎釜鏃跺€欎細鏈変竴涓棶棰橈紝鐐瑰嚮 鎶?code>鏈湴璧勬簮鏂囦欢涔熶笂浼犲埌鏈嶅姟鍣紝 浣跨敤鍥剧墖璧勬簮鐨勬椂鍊欐寚瀹?code>Package鍖呭悕 杩欓噷鐨勫浘鐗囪祫婧愬紩鐢?code>鎸囧畾鍒颁簡鍏蜂綋鍥剧墖锛屼笉鎺ㄨ崘杩欑鏂瑰紡銆?/p>
涓嬮潰涓昏鏄坊鍔犱娇鐢ㄧず渚嬭繘琛屼紭鍖栵紝鎻愬崌鍖呯殑璇勫垎 鏂板缓 鏌ョ湅 鍦ㄥ紑鍙戝師鐢熷簲鐢ㄦ椂锛屾瘡娆′慨鏀逛唬鐮佸悗閮介渶瑕侀噸鏂扮紪璇戯紝鑰屼笖杩愯鍒扮‖浠惰澶囦笂锛涚敱浜?code>Flutter鏀寔 鐢变簬 浠?code>server绔?/code>鍦ㄨ繍琛岋紝瀹為檯涓婃寕杞界殑鏄?code>hotload_demo宸ョ▼锛涗笅闈㈣繘琛岄獙璇?/p>
瀹炵幇浜嗕笂闈㈢殑$ flutter packages pub publish --server=https://pub.dartlang.org
璇佷功闂鎶ラ敊
Github
浠撳簱涓垱寤恒€?/p>
Github
鑾峰彇璇佷功LICENSE
鏂囦欢銆?/p>
20 ~ 25鍒嗛挓
锛宲ub.dev缃戠珯灏辫兘鎼滅储鍒版垜浠彂甯冪殑logic_package_demo
鍖呫€?/p>
wechat_demo浣跨敤鎴戜滑鍙戝竷鐨勫寘
pubspec.yaml
鏂囦欢杩涜閰嶇疆锛岀偣鍑?code>Pub get寮曞叆
friends_page.dart
鏂囦欢杩涜寮曞叆浣跨敤// 瀵煎叆澶存枃浠?
import 'package:login_package_demo/login_package_demo.dart' as login;
Pub get
鐨勬椂鍊欏彧鏄妸浠g爜寮曞叆鍒颁簡wechat_demo
椤圭洰锛屽浘鐗囪祫婧愬苟娌℃湁寮曞叆锛岃繖涓椂鍊欎娇鐢?code>Package鍖呭氨浼氭姤閿欙紝涓嬮潰杩涜浼樺寲...浼樺寲package
璁╀娇鐢ㄨ€呰兘澶熸垚鍔熷紩鍏ュ浘鐗囪祫婧?/code>
images
鍥剧墖璧勬簮瑕佹斁鍏?code>lib鐩綍涓?br>
// 鍘籰ogic_package_demo鍖呬腑鎵惧埌鍥剧墖杩涜鍔犺浇
const AssetImage('images/bubble.png', package: 'logic_package_demo'),
logic_package_demo
鍖咃紙pubspec.yaml鏂囦欢瑕佹妸version: 0.0.1 鏇存敼涓?0.0.2 # 椤圭洰鐗堟湰锛岃繘琛岀増鏈崌绾э紝鍚﹀垯涓嶈兘鍙戝竷锛?/li>
logic_package_demo.dart
涓殑IndexBar
杩涜鎵╁睍锛屽厑璁稿闈紶鍏ュ浘鐗?/li>
class IndexBar extends StatefulWidget {
// 瀵瑰鎻愪緵鍥炶皟锛屽憡璇塮riends_page褰撳墠閫変腑鐨勬槸鏍囪瘑
final void Function(String str) indexBarCallBack;
final ImageProviderimage;
const IndexBar({required this.indexBarCallBack, this.image, Keykey}) : super(key: key);
......
// 璁╂皵娉″眳涓?
alignment: Alignment(-0.2, 0),
children: [
Image(
// widget.image浣跨敤澶栭潰浼犲叆鐨刬mage
image: widget.image ?AssetImage('images/姘旀场.png', package: 'logic_package_demo'),
width: 60,
),
Text(
_indicatorText,
style: TextStyle(fontSize: 35, color: Colors.white),
)
],
Pub.dev
缃戠珯鏌ョ湅鎻愬崌鍖呯殑鍒嗘暟杩涜浼樺寲
example
锛屼娇鐢?code>Package鍖呯殑绀轰緥API
鏁伴噺
package_example
绌哄伐绋嬶紝璺?code>logic_package_demo鏀惧叆鍚屼竴鐩綍涓?/li>
pubspec.yaml
鏂囦欢杩涜閰嶇疆锛屽苟鐐瑰嚮Pub get
杩涜寮曞叆
wechat_demo
涓殑FriendsPage
椤甸潰锛屽苟杩涜淇敼<!-- package_example宸ョ▼鐨刴ain.dart鏂囦欢 -->
import 'package:flutter/material.dart';
import 'package:logic_package_demo/logic_package_demo.dart' as logic;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Keykey}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FriendsPage(),
);
}
}
class _FriendCell extends StatelessWidget {
const _FriendCell(
{this.imageUrl, this.name, this.groupTitle, this.imageAssets});
final StringimageUrl;
final Stringname;
final StringgroupTitle;
final StringimageAssets;
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 10),
height: groupTitle != null 30 : 0,
// 浣跨敤logic_package_demo搴撲腑閰嶇疆鐨勫父閲?
color: logic.WeChatThemeColor,
child: groupTitle != null
Text(
groupTitle!,
style: const TextStyle(color: Colors.grey),
)
: null,
), //澶撮儴
Container(
color: Colors.white,
child: Row(
children: [
Container(
margin: EdgeInsets.all(10),
width: 34,
height: 34,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
image: DecorationImage(
image: imageUrl != null
NetworkImage(imageUrl!)
: AssetImage(imageAssets!,
package: 'logic_package_demo') as ImageProvider,
)),
), //鍥剧墖
Container(
// color: Colors.red,
width: logic.screenWidth(context) - 54,
child: Column(
children: [
Container(
alignment: Alignment.centerLeft,
height: 54,
child: Text(
name!,
style: TextStyle(fontSize: 18),
),
),
Container(
height: 0.5,
color: logic.WeChatThemeColor,
), //涓嬪垝绾?
],
),
), //鏄电О+涓嬪垝绾?
],
),
), //Cell鐨勫唴瀹?
],
);
}
}
class FriendsPage extends StatefulWidget {
@override
_FriendsPageState createState() => _FriendsPageState();
}
class _FriendsPageState extends State<FriendsPage>
with AutomaticKeepAliveClientMixin<FriendsPage> {
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
double _cellHeight = 54.5;
double _groupHeight = 30.0;
//瀛楀吀锛岄噷闈㈡斁item鍜岄珮搴︾殑瀵瑰簲鐨勬暟鎹€?
final Map _groupOffsetMap = {
logic.INDEX_WORDS[0]: 0.0,
logic.INDEX_WORDS[1]: 0.0,
};
final List<Friends> _headerData = [
Friends(imageAssets: 'images/鏂扮殑鏈嬪弸.png', name: '鏂扮殑鏈嬪弸'),
Friends(imageAssets: 'images/缇よ亰.png', name: '缇よ亰'),
Friends(imageAssets: 'images/鏍囩.png', name: '鏍囩'),
Friends(imageAssets: 'images/鍏紬鍙?png', name: '鍏紬鍙?),
];
final List<Friends> _listDatas = [];
// 鎳掑姞杞?
late ScrollController _scrollController;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
//鍒涘缓鏁版嵁
_listDatas
..addAll(datas)
..addAll(datas);
//鎺掑簭
_listDatas.sort((Friends a, Friends b) {
return a.indexLetter!.compareTo(b.indexLetter!);
});
var _groupOffset = _cellHeight * _headerData.length;
//杩涜繃寰幆璁$畻锛屽皢姣忎竴涓ご鐨勪綅缃畻鍑烘潵銆傛斁鍏ュ瓧鍏?
for (int i = 0; i < _listDatas.length; i++) {
if (i < 1) {
//绗竴涓猚ell涓€瀹氭湁澶达紒
_groupOffsetMap.addAll({_listDatas[i].indexLetter: _groupOffset});
//淇濆瓨瀹屼簡鍐嶅姞_groupOffset
_groupOffset += _cellHeight + _groupHeight;
} else if (_listDatas[i].indexLetter == _listDatas[i - 1].indexLetter) {
//涓嶅悓瀛橈紝鍙渶瑕佸姞Cell鐨勯珮搴?
_groupOffset += _cellHeight;
} else {
_groupOffsetMap.addAll({_listDatas[i].indexLetter: _groupOffset});
//淇濆瓨瀹屼簡鍐嶅姞_groupOffset
_groupOffset += _cellHeight + _groupHeight;
}
}
}
Widget _itemForRow(BuildContext context, int index) {
//鏄剧ず澶撮儴4涓狢ell
if (index < _headerData.length) {
return _FriendCell(
imageAssets: _headerData[index].imageAssets,
name: _headerData[index].name,
);
}
//鏄惁鏄剧ず缁勫悕瀛楋紒
bool _hiddenIndexLetter = (index - 4 > 0 &&
_listDatas[index - 4].indexLetter == _listDatas[index - 5].indexLetter);
return _FriendCell(
imageUrl: _listDatas[index - 4].imageUrl,
name: _listDatas[index - 4].name,
groupTitle: _hiddenIndexLetter null : _listDatas[index - 4].indexLetter,
);
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
appBar: AppBar(
backgroundColor: logic.WeChatThemeColor,
title: Text('閫氳褰?),
),
body: Stack(
children: [
Container(
color: logic.WeChatThemeColor,
child: ListView.builder(
controller: _scrollController,
itemBuilder: _itemForRow,
itemCount: _listDatas.length + _headerData.length,
),
), //鍒楄〃
logic.IndexBar(
indexBarCallBack: (String str) {
if (_groupOffsetMap[str] != null) {
_scrollController.animateTo(_groupOffsetMap[str],
duration: Duration(microseconds: 100),
curve: Curves.easeIn);
}
},
), //鎮诞鐨勭储寮曟潯
],
));
}
}
class Friends {
Friends({this.imageUrl, this.name, this.indexLetter, this.imageAssets});
final StringimageAssets;
final StringimageUrl;
final Stringname;
final StringindexLetter;
}
List<Friends> datas = [
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/27.jpg',
name: 'Lina',
indexLetter: 'L'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/17.jpg',
name: '鑿插効',
indexLetter: 'F'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/16.jpg',
name: '瀹夎帀',
indexLetter: 'A'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/31.jpg',
name: '闃胯吹',
indexLetter: 'A'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/22.jpg',
name: '璐濇媺',
indexLetter: 'B'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/37.jpg',
name: 'Lina',
indexLetter: 'L'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/18.jpg',
name: 'Nancy',
indexLetter: 'N'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/47.jpg',
name: '鎵f墸',
indexLetter: 'K'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/3.jpg',
name: 'Jack',
indexLetter: 'J'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/5.jpg',
name: 'Emma',
indexLetter: 'E'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/24.jpg',
name: 'Abby',
indexLetter: 'A'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/15.jpg',
name: 'Betty',
indexLetter: 'B'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/13.jpg',
name: 'Tony',
indexLetter: 'T'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/26.jpg',
name: 'Jerry',
indexLetter: 'J'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/men/36.jpg',
name: 'Colin',
indexLetter: 'C'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/12.jpg',
name: 'Haha',
indexLetter: 'H'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/11.jpg',
name: 'Ketty',
indexLetter: 'K'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/13.jpg',
name: 'Lina',
indexLetter: 'L'),
Friends(
imageUrl: 'https://randomuser.me/api/portraits/women/23.jpg',
name: 'Lina',
indexLetter: 'L'),
];
package_example
宸ョ▼娌℃湁閰嶇疆assets
瀵艰嚧椤甸潰鍥剧墖鍔犺浇涓嶅嚭鏉?/li>
// image涓巌con閮借缃垚鍙€夌殑
class IndexBar extends StatefulWidget {
final void Function(String str) indexBarCallBack;
final ImageProviderimage;
final Iconicon;
const IndexBar(
{required this.indexBarCallBack, this.image, this.icon, Keykey})
: super(key: key);
......
alignment: const Alignment(-0.2, 0),
children: [
// 浼爄con灏辨樉绀篿con锛屼紶image灏辨樉绀篿mage锛岄兘涓嶄紶鐨勮瘽鏄剧ず閾哄簳鍥剧墖
widget.icon
Image(
image: widget.image
const AssetImage('images/bubble.png',
package: 'logic_package_demo'),
width: 60,
),
Text(
_indicatorText,
style:
const TextStyle(fontSize: 35, color: Colors.white),
)
],
package_example
宸ョ▼閲嶆柊Pub get
瀵煎叆logic_package_demo
搴?/li>
package_example
宸ョ▼鍒犻櫎涓嬪浘涓皵娉″浘鐗?/code>杩涜娴嬭瘯
pubspec.yaml
鏂囦欢杩涜閰嶇疆锛岄噸鏂拌繍琛屽伐绋?/li>
package_example
宸ョ▼鐨?code>main.dart鏂囦欢class _FriendCell extends StatelessWidget {
......
Container(
margin: EdgeInsets.all(10),
width: 34,
height: 34,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
image: DecorationImage(
image: imageUrl != null
NetworkImage(imageUrl!)
// 鏈湴鍥剧墖鎸囧畾鍒發ogic_package_demo鍖?
: AssetImage(imageAssets!,
package: 'logic_package_demo') as ImageProvider,
)),
), //鍥剧墖
logic_package_demo
宸ョ▼鏂板缓example
鐩綍锛屾妸package_example
绀轰緥宸ョ▼涓殑main.dart
鏂囦欢瀵煎叆銆?/p>
logic_package_demo.dart
鏂囦欢涓唬鐮佸お澶氾紝鎴戜滑杩涜鎷嗗垎瀵瑰簱杩涜浼樺寲
鏂板缓index_bar.dart
鏂囦欢锛屾妸logic_package_demo.dart
鏂囦欢涓唬鐮佹娊鍙栧嚭鏉?/li>
<!-- logic_package_demo.dart鏂囦欢 -->
library logic_package_demo;
// 搴撲腑瀵煎叆鍗冲彲
import 'package:flutter/material.dart';
part 'index_bar.dart';
<!-- index_bar.dart鏂囦欢 -->
// 鎸囧畾灞炰簬鍝釜搴?
part of 'logic_package_demo.dart';
class IndexBar extends StatefulWidget {
final void Function(String str) indexBarCallBack;
final ImageProviderimage;
final Iconicon;
const IndexBar(
{required this.indexBarCallBack, this.image, this.icon, Keykey})
: super(key: key);
@override
_IndexBarState createState() => _IndexBarState();
}
//鑾峰彇閫変腑鐨処tem鐨勫瓧绗︼紒锛?
int getIndex(BuildContext context, Offset globalPosition) {
//鎷垮埌鐐瑰墠灏忛儴浠剁殑鐩掑瓙
RenderBox box = context.findRenderObject() as RenderBox;
//鎷垮埌y鍊硷紝globalToLocal褰撳墠浣嶇疆鎴戦儴浠剁殑鍘熺偣(灏忛儴浠跺乏涓婅)鐨勮窛绂伙紙x,y锛?
double y = box.globalToLocal(globalPosition).dy;
//绠楀嚭瀛楃楂樺害
var itemHeight = screenHeight(context) / 2 / INDEX_WORDS.length;
//绠楀嚭绗嚑涓猧tem
int index = (y ~/ itemHeight).clamp(0, INDEX_WORDS.length - 1);
return index;
}
class _IndexBarState extends State<IndexBar> {
Color _bkColor = Color.fromRGBO(1, 1, 1, 0.0);
Color _textColor = Colors.black;
double _indicatorY = 0.0;
String _indicatorText = 'A';
bool _indicatorHidden = true;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
final List<Widget> words = [];
for (int i = 0; i < INDEX_WORDS.length; i++) {
words.add(Expanded(
child: Text(
INDEX_WORDS[i],
style: TextStyle(fontSize: 10, color: _textColor),
)));
}
return Positioned(
right: 0.0,
top: screenHeight(context) / 8,
height: screenHeight(context) / 2,
width: 120,
child: Row(
children: [
Container(
alignment: Alignment(0, _indicatorY),
width: 100,
// color: Colors.red,
child: _indicatorHidden
null
: Stack(
alignment: const Alignment(-0.2, 0),
children: [
widget.icon
Image(
image: widget.image
const AssetImage('images/bubble.png',
package: 'logic_package_demo'),
width: 60,
),
Text(
_indicatorText,
style:
const TextStyle(fontSize: 35, color: Colors.white),
)
],
),
), //鎸囩ず鍣?
GestureDetector(
onVerticalDragUpdate: (DragUpdateDetails details) {
int index = getIndex(context, details.globalPosition);
widget.indexBarCallBack(INDEX_WORDS[index]);
setState(() {
_indicatorY = 2.2 / INDEX_WORDS.length * index - 1.1;
_indicatorText = INDEX_WORDS[index];
_indicatorHidden = false;
});
},
onVerticalDragDown: (DragDownDetails details) {
int index = getIndex(context, details.globalPosition);
widget.indexBarCallBack(INDEX_WORDS[index]);
setState(() {
_indicatorY = 2.2 / INDEX_WORDS.length * index - 1.1;
_indicatorText = INDEX_WORDS[index];
_indicatorHidden = false;
_bkColor = Color.fromRGBO(1, 1, 1, 0.5);
_textColor = Colors.white;
});
},
onVerticalDragEnd: (DragEndDetails details) {
setState(() {
_indicatorHidden = true;
_bkColor = Color.fromRGBO(1, 1, 1, 0.0);
_textColor = Colors.black;
});
},
child: Container(
width: 20,
color: _bkColor,
child: Column(
children: words,
),
),
), //绱㈠紩鏉?
],
),
);
}
}
//涓婚鑹?
const Color WeChatThemeColor = Color.fromRGBO(220, 220, 220, 1.0);
//灞忓箷瀹介珮
double screenWidth(BuildContext context) => MediaQuery.of(context).size.width;
double screenHeight(BuildContext context) => MediaQuery.of(context).size.height;
const INDEX_WORDS = [
'馃攳',
'鈽?,
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z'
];
pubspec.yaml
鏂囦欢涓?code>CHANGELOG.md鏂囦欢涓殑鐗堟湰鍙蜂负1.0.0
锛岀劧鍚庢墽琛?code>鍙戝竷鍛戒护
plugin寮€鍙?/h2>
logic_plugin_demo
宸ョ▼鎻掍欢宸ョ▼
鐩綍锛岃嚜甯?code>example绀轰緥鐩綍锛屽叾涓?code>ios銆?code>android鐩綍涓嬪苟涓嶅寘鍚伐绋嬶紝鍙槸鍚勪釜骞冲彴鐨勪唬鐮?/p>
pubspec.yaml
鏂囦欢閰嶇疆homepage
Plugin鎻掍欢寮€鍙?/h6>
logic_plugin_demo.dart
鏂囦欢缂栧啓浠g爜濡備笅import 'dart:async';
import 'package:flutter/services.dart';
class LogicPluginDemo {
static const MethodChannel _channel =
const MethodChannel('logic_plugin_demo');
static Future<String?> get platformVersion async {
final Stringversion = await _channel.invokeMethod('getPlatformVersion');
return version;
}
// 鑾峰彇鐢垫睜鐢甸噺
static Future<String?> get platformBatteryLevel async {
int batteryLevel = await _channel.invokeMethod('getPlatformBatteryLevel');
return batteryLevel.toString();
}
}
ios/Classes
鐩綍涓嬬殑LogicPluginDemoPlugin.m
鏂囦欢淇敼浠g爜濡備笅锛屼互鎺ユ敹Flutter
鍙戦€佽繃鏉ョ殑娑堟伅#import "LogicPluginDemoPlugin.h"
@implementation LogicPluginDemoPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"logic_plugin_demo"
binaryMessenger:[registrar messenger]];
LogicPluginDemoPlugin* instance = [[LogicPluginDemoPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
// 鎺ユ敹Flutter鍙戦€佽繃鏉ョ殑鑾峰彇鐢垫睜鐢甸噺娑堟伅
} else if([@"getPlatformBatteryLevel" isEqualToString:call.method]){
int batteryLevel = [self getBatteryLevel];
// 鎶婂€煎寘瑁呮垚瀵硅薄杩斿洖鍑哄幓
result(@(batteryLevel));
}else{
result(FlutterMethodNotImplemented);
}
}
-(int)getBatteryLevel{
UIDevice * device = UIDevice.currentDevice;
device.batteryMonitoringEnabled = YES;
if (device.batteryLevel == UIDeviceOrientationUnknown) {
return -1;
}else{
return (int)(device.batteryState * 100);
}
}
@end
example/lib/main.dart
鏂囦欢涓繘琛岃皟璇?/li>
example/ios
鐩綍涓嬬殑Runner
宸ョ▼锛屼娇鐢ㄧ湡鏈烘煡鐪嬭幏鍙栫數閲忔儏鍐?/li>
logic_plugin_demo
鎻掍欢杩涜鍙戝竷// 妫€鏌lugin鍖?
$ flutter packages pub publish --dry-run
// 鎸囧畾鏈嶅姟鍣ㄥ彂甯?
$ flutter packages pub publish --server=https://pub.dartlang.org
Plugin
鎻掍欢鐨勫彂甯冧笌Package
鍖呯殑鍙戝竷鏄竴鏍风殑锛?code>娉ㄦ剰閰嶇疆璇佷功锛堝悓涓婏級銆?/p>
鐑噸杞芥寕杞?/h2>
鐑噸杞藉垵鎺?/h6>
Flutter
鏄竴濂楀叏鏂扮殑璺ㄥ钩鍙版柟妗堬紝Flutter
骞朵笉鍍?code>React Native閭f牱渚濊禆鍘熺敓搴旂敤鐨勬覆鏌擄紝鑰屾槸鑷繁鏈変竴濂楁覆鏌撳紩鎿庯紝骞朵娇鐢?code>Dart褰撲綔Flutter
鐨勫紑鍙戣瑷€銆?code>Flutter鏁翠綋妗嗘灦鍒嗕负涓ゅ眰锛屽簳灞傛槸閫氳繃C++
瀹炵幇鐨勫紩鎿庨儴鍒嗭紝Skia
鏄?code>Flutter鐨勬覆鏌撳紩鎿庯紝璐熻矗璺ㄥ钩鍙扮殑鍥惧舰娓叉煋銆?code>Dart浣滀负Flutter
鐨勫紑鍙戣瑷€锛屽湪C++
寮曟搸涓婂眰鏄?code>Dart鐨?code>Framework銆?/p>
Flutter
鏀寔浜氱绾х儹閲嶈浇锛?code>Android Studio鍜?code>VSCode閮芥敮鎸?code>Hot Reload鐨勭壒鎬э紱浣嗛渶瑕佸尯鍒嗙殑鏄?code>鐑噸杞藉拰鐑洿鏂版槸涓や釜涓嶅悓鐨勬蹇?/code>
鐑噸杞?/code>鏄湪杩愯璋冭瘯鐘舵€佷笅锛屽皢鏂颁唬鐮佺洿鎺ユ洿鏂板埌鎵ц涓殑浜岃繘鍒?/li>
鐑洿鏂?/code>鏄湪涓婄嚎鍚庯紝閫氳繃
Runtime
鎴栧叾浠栨柟寮忥紝鏀瑰彉鐜版湁鎵ц閫昏緫鐑噸杞界殑鎼缓鏄彲浠ュ仛鍒扮儹鏇存柊鐨?/code>
AOT 銆丣IT
Flutter
鏀寔AOT
锛圓head of time锛夊拰JIT
锛圝ust in time锛変袱绉嶇紪璇戞ā寮?/p>
JIT妯″紡
鏀寔鍦ㄨ繍琛岃繃绋嬩腑杩涜Hot Reload
锛屽埛鏂拌繃绋嬫槸涓€涓閲忕殑杩囩▼锛岀敱绯荤粺瀵规湰娆″拰涓婃鐨勪唬鐮佸仛涓€娆?code>snapshot锛屽皢鏂扮殑浠g爜娉ㄥ叆鍒?code>DartVM涓繘琛屽埛鏂帮紝浣嗘湁鏃朵細涓嶈兘杩涜Hot Reload
锛屾鏃惰繘琛屼竴娆″叏閲忕殑Hot Reload
鍗冲彲AOT妯″紡
鍒欐槸鍦ㄨ繍琛屽墠棰勫厛缂栬瘧濂斤紝杩欐牱鍦ㄦ瘡娆¤繍琛岃繃绋嬩腑灏变笉闇€瑕佽繘琛屽垎鏋愩€佺紪璇戙€佹妯″紡鐨勮繍琛岄€熷害鏄渶蹇殑銆?/li>
Flutter
鍚屾椂閲囩敤浜嗕袱绉嶆柟妗堬紝鍦ㄥ紑鍙戦樁娈甸噰鐢?code>JIT妯″紡杩涜寮€鍙戯紱鍦?code>release闃舵閲囩敤AOT妯″紡
锛屽皢浠g爜鎵撳寘涓轰簩杩涘埗杩涜鍙戝竷銆?/p>
Hot Reload
锛屽彲浠ヨ繘琛岀儹閲嶈浇锛屽椤圭洰鐨勫紑鍙戞晥鐜囨湁寰堝ぇ鐨勬彁鍗囥€?/p>
Flutter
瀹炵幇鏈哄埗鏀寔JIT
鐨勫師鍥狅紝鐞嗚涓婃潵璇存槸鏀寔鐑洿鏂颁互鍙婃湇鍔″櫒涓嬪彂浠g爜鐨勶紱浣嗘槸鐢变簬杩欐牱浼氫娇鎬ц兘鍙樺樊锛岃€屼笖杩樻湁瀹℃牳闂锛屾墍浠?code>Flutter娌℃湁閲囩敤杩欑鏂规銆?/p>
鐑噸杞?/code>鏈川灏辨槸閫氳锛?code>server绔?/code>涓?code>Dart绔?/code>涔嬮棿杩涜閫氳锛屾帴鏀跺埌
鎵撳紑
Dart绔?/code>鍙戠敓浜嗗彉鍖栵紝鏈嶅姟绔細鍛婅瘔
宸ョ▼
Flutter.framework
鍘昏繘琛屾覆鏌?/p>
App
绫诲瀷宸ョ▼hotload_demo
~/flutter/packages/flutter_tools
锛屾妸flutter_tools
鐩綍鍐呭鐢?code>Android Studio
flutter_tools
宸ョ▼灏辩浉褰撲簬server绔?/code>锛?code>hotload_demo
宸ョ▼灏辩浉褰撲簬app绔?/code>锛?/li>
flutter_tools
娣诲姞Dart Command Line App
Dart SDK Path
锛岄€夋嫨Android Studio
-> Preferences...
flutter_tools
宸ョ▼
hotload_demo
宸ョ▼椤甸潰title
杩愯鍛戒护
鏌ョ湅title
鐑噸杞芥寕杞?/code>锛屾垜浠氨鍙互鍦?code>flutter_tools.dart
鏂囦欢涓坊鍔犳柇鐐硅皟璇?code>鐑噸杞界殑鍘熺悊銆?/p>