去年今日此门中,人面桃花相映红
人面不知何处去,桃花依旧笑春风
实现样式
支持功能
支持左右滑动
支持拖拽结束后停留在固定位置
边界处理
代码实现
拖拽条封装成了一个 widget:HousePrice
注意:ColorUtil
是一个第三方颜色插件,需要安装:flutter_color_plugin
class HousePrice extends StatefulWidget {
@override
_HousePriceState createState() => _HousePriceState();
}
class _HousePriceState extends State<HousePrice> {
String _leftPrice = '0';
String _rightPrice = '不限';
double _leftImageMargin = 20;
double _rightImageMargin = 20;
double _leftBlackLineW = 0; // 左边黑线的宽度
double _rightBlackLineW = 0; // 右边黑线的宽度
int _leftImageCurrentIndex = 0; // 左边选中的价格索引
int _rightImageCurrentIndex = 0; // 右边选中的价格索引
@override
Widget build(BuildContext context) {final screenWidth = MediaQuery.of(context).size.width;
return Container(
color: Colors.white,
child: Column(
children: <Widget>[_priceRangeBlock(),
SizedBox(height: 10,),
_priceBlock(_leftPrice, _rightPrice),
SizedBox(height: 10,),
Stack(
children: <Widget>[_lineBlock(context, screenWidth),
_leftImageBlock(context, screenWidth),
_rightImageBlock(context, screenWidth),
],
),
SizedBox(height: 10,),
_priceBottomBlock(context)
],
),
);
}
/*
* title 模块
* */
_priceRangeBlock() {
return Row(
children: <Widget>[
SizedBox(width: 20,),
Text(
'价格范围',
style: TextStyle(
fontSize: 15,
color: ColorUtil.color('#212121'),
fontFamily: 'PingFangSC-Semibold',
fontWeight: FontWeight.bold,
),
),
],
);
}
/*
* 价格区间
* leftPrice:选中的起始价格
* rightPrice:选中的最大价格
* */
_priceBlock(String leftPrice, String rightPrice) {
return Row(
children: <Widget>[
SizedBox(width: 20,),
Text(
'$leftPrice-$rightPrice',
style: TextStyle(
fontSize: 12,
color: ColorUtil.color('#757575'),
fontFamily: 'PingFangSC-Regular',
),
),
],
);
}
/*
* 横线视图模块, 包括黄色横线和黑色横线
* */
_lineBlock(BuildContext context, double screenWidth) {
return Row(
children: <Widget>[
SizedBox(width: 20,),
Stack(
children: <Widget>[
Container(// 黄色横线
color: Colors.white,
height: 30,
width: screenWidth - 40,
alignment: Alignment.center,
child: Container(color: ColorUtil.color('#FED836'),
height: 4,
width: screenWidth - 40,
),
),
Positioned(// 左边黑色横线
left: 0,
top: 13,
child:Container(
height: 4,
width: _leftBlackLineW,
decoration: BoxDecoration(
color: Colors.white,
border: Border(left: BorderSide(color: Colors.black, width: 1), top: BorderSide(color: Colors.black, width: 1), bottom: BorderSide(color: Colors.black, width: 1))
),
)
),
Positioned(// 右边黑色横线
right: 0,
top: 13,
child:Container(
height: 4,
width: _rightBlackLineW,
decoration: BoxDecoration(
color: Colors.white,
border: Border(right: BorderSide(color: Colors.black, width: 1), top: BorderSide(color: Colors.black, width: 1), bottom: BorderSide(color: Colors.black, width: 1))
),
)
),
],
),
],
);
}
/*
* 左边 image 滑块,使用到:_imageItem
* */
_leftImageBlock(BuildContext context, double screenWidth) {double singleW = (screenWidth-40)/6;
return Positioned(
left: _leftImageMargin,
top: 0,
child: GestureDetector(child: _imageItem(),
// 水平方向移动
onHorizontalDragUpdate: (DragUpdateDetails details) {print('拖拽中');
if(_leftImageMargin < 20) {// 处理左边边界
_leftImageMargin = 20;
_leftBlackLineW = 2;
} else if (((screenWidth-(_rightImageMargin+30))-(_leftImageMargin+30))<(singleW-45)) {// 处理两球相遇情况
_leftImageMargin = screenWidth-(_rightImageMargin+singleW+15);
_leftBlackLineW = _leftImageMargin-20;
} else {
_leftImageMargin += details.delta.dx;
_leftBlackLineW = _leftImageMargin-20 >= 0 ? _leftImageMargin-20 : 2;
}
setState(() {});// 刷新 UI
},
onHorizontalDragEnd: (DragEndDetails details) {double singleW = (screenWidth-40)/6;
double _leftImageMarginFlag = _leftImageMargin;
print('拖拽结束');
if(_leftImageMarginFlag <singleW/2) {
_leftImageMargin = 20;
_leftBlackLineW = 2;
_leftImageCurrentIndex = 0;
_leftPrice = '¥0';
} else if (_leftImageMarginFlag <singleW*1.5) {
_leftImageMargin = singleW+5;
_leftBlackLineW = _leftImageMargin;
_leftImageCurrentIndex = 1;
_leftPrice = '¥200';
} else if (_leftImageMarginFlag < singleW*2.5) {
_leftImageMargin = singleW*2+5;
_leftBlackLineW = _leftImageMargin;
_leftImageCurrentIndex = 2;
_leftPrice = '¥300';
} else if (_leftImageMarginFlag < singleW*3.5) {
_leftImageMargin = singleW*3+5;
_leftBlackLineW = _leftImageMargin;
_leftImageCurrentIndex = 3;
_leftPrice = '¥400';
} else if (_leftImageMarginFlag < singleW*4.5) {
_leftImageMargin = singleW*4+5;
_leftBlackLineW = _leftImageMargin;
_leftImageCurrentIndex = 4;
_leftPrice = '¥500';
} else if (_leftImageMarginFlag < singleW*5.5) {
_leftImageMargin = singleW*5+5;
_leftBlackLineW = _leftImageMargin;
_leftImageCurrentIndex = 5;
_leftPrice = '¥600';
} else { }
print('选中第 $_leftImageCurrentIndex 个');
setState(() {});// 刷新 UI
},
)
);
}
/*
* 右边 image 滑块,使用到:_imageItem
* */
_rightImageBlock(BuildContext context, double screenWidth) {double singleW = (screenWidth-40)/6;
return Positioned(
right: _rightImageMargin,
top: 0,
child: GestureDetector(child: _imageItem(),
// 水平方向移动
onHorizontalDragUpdate: (DragUpdateDetails details) {print(_rightImageMargin);
if(_rightImageMargin < 20) {// 处理右边边界
_rightImageMargin = 20;
_rightBlackLineW = 2;
} else if(((screenWidth-(_rightImageMargin+30))-(_leftImageMargin+30))<(singleW-45)) { // 处理两球相遇情况
_rightImageMargin = screenWidth-(_leftImageMargin+15+singleW);
_rightBlackLineW = _rightImageMargin-20;
} else {
_rightImageMargin -= details.delta.dx;
_rightBlackLineW = _rightImageMargin-20 >= 0 ? _rightImageMargin-20 : 2;
}
setState(() {}); // 刷新 UI
},
onHorizontalDragEnd: (DragEndDetails details){double singleW = (screenWidth-40)/6;
double _rightImageMarginFlag = _rightImageMargin;
print('拖拽结束');
if(_rightImageMarginFlag <singleW/2) {
_rightImageMargin = 20;
_rightBlackLineW = 2;
_rightImageCurrentIndex = 0;
_rightPrice = '不限';
} else if (_rightImageMarginFlag <singleW*1.5) {
_rightImageMargin = singleW+5;
_rightBlackLineW = _rightImageMargin;
_rightImageCurrentIndex = 1;
_rightPrice = '¥600';
} else if (_rightImageMarginFlag < singleW*2.5) {
_rightImageMargin = singleW*2+5;
_rightBlackLineW = _rightImageMargin;
_rightImageCurrentIndex = 2;
_rightPrice = '¥500';
} else if (_rightImageMarginFlag < singleW*3.5) {
_rightImageMargin = singleW*3+5;
_rightBlackLineW = _rightImageMargin;
_rightImageCurrentIndex = 3;
_rightPrice = '¥400';
} else if (_rightImageMarginFlag < singleW*4.5) {
_rightImageMargin = singleW*4+5;
_rightBlackLineW = _rightImageMargin;
_rightImageCurrentIndex = 4;
_rightPrice = '¥300';
} else if (_rightImageMarginFlag < singleW*5.5) {
_rightImageMargin = singleW*5+5;
_rightBlackLineW = _rightImageMargin;
_rightImageCurrentIndex = 5;
_rightPrice = '¥200';
}
print('选中第 $_rightImageCurrentIndex 个');
setState(() {});// 刷新 UI
},
),
);
}
// 滑块的 image
_imageItem(){
return Image.asset(
'assets/images/house_price_sliding.png',
width: 30,
height: 30,
);
}
/*
* 底部价格大模块,使用到:_priceItem,_priceTitleList
* */
_priceBottomBlock(BuildContext context) {final screenWidth = MediaQuery.of(context).size.width;
final singleW = (screenWidth-40)/6;
double margin = 14.5;
return Stack(
children: <Widget>[
Container(
color: Colors.white,
height: 17,
width: screenWidth-40,
),
Positioned(
left: 7.5,
top: 0,
child: _priceItem(_priceTitleList[0]),
),
Positioned(
left: singleW-margin,
top: 0,
child: _priceItem(_priceTitleList[1]),
),
Positioned(
left: singleW*2-margin,
top: 0,
child: _priceItem(_priceTitleList[2]),
),
Positioned(
left: singleW*3-margin,
top: 0,
child: _priceItem(_priceTitleList[3]),
),
Positioned(
left: singleW*4-margin,
top: 0,
child: _priceItem(_priceTitleList[4]),
),
Positioned(
left: singleW*5-margin,
top: 0,
child: _priceItem(_priceTitleList[5]),
),
Positioned(
right: 3,
bottom: 1,
child: _priceItem(_priceTitleList[6]),
),
],
);
}
/*
* 底部价格每个 item
* */
_priceItem(String title) {
return Text(
title,
style: TextStyle(color: ColorUtil.color('#212121'),
fontFamily: 'PingFangSC-Regular',
fontSize: 12,
),
);
}
/*
* 价格选择的数组
* */
List<String> _priceTitleList = <String>['¥0', '¥200', '¥300', '¥400', '¥500', '¥600', '不限'];
}