Flutter 项目实战 高德定位计算距离并展示首页数据 (六)
注册高德地图获取定位信息并通过经纬度计算距离插入到MySQL数据库......
·
/ 注册高德地图 (安卓) /
Android Studio 创建签名文件
创建密钥 (Create New Key Store) 签署您的应用程序
创建密钥并存储到制定的路径
创建应用并生成key
注册高德地图开发者账户 Android 如何获取 SHA1 值?
/ 获取定位信息 /
集成高德定位Flutter插件
打开 pubspec.yaml 文件 添加 amap_flutter_location (高德定位)、permission_handler (应用权限)、app_settings (app权限设置) 、location_service_check (是否开通gps) 插件依赖配置
amap_flutter_location: any # 高德Flutter定位插件 permission_handler: any #应用权限 app_settings: any #app权限设置 location_service_check: any #是否开通GPS判断是否开启定位权限
/// 申请定位权限 /// 授予定位权限返回true, 否则返回false Future<bool> requestLocationPermission() async { //获取当前的权限 var status = await Permission.location.status; if (status == PermissionStatus.granted) { //已经授权 return true; } else { //未授权则发起一次申请 status = await Permission.location.request(); if (status == PermissionStatus.granted) { return true; } else { return false; } } }判断是否开启GPS
... bool _isOpenGps = await LocationServiceCheck.checkLocationIsOpen; if(!_isOpenGps) { logV("定位权限申请通过"); AppSettings.openLocationSettings(); } ...动态申请定位权限
/// 动态申请定位权限 Future<bool> requestPermission() async { // 申请权限 bool hasLocationPermission = await requestLocationPermission(); if (hasLocationPermission) { bool _isOpenGps = await LocationServiceCheck.checkLocationIsOpen; if(!_isOpenGps) { logV("定位权限申请通过"); AppSettings.openLocationSettings(); } return _isOpenGps; } else { logV("定位权限申请不通过"); // 跳转到系统设置页 AppSettings.openAppSettings(); } return hasLocationPermission; }高德地图初始化
StreamSubscription<Map<String, Object>>? _locationListener; AMapFlutterLocation? _locationPlugin = AMapFlutterLocation(); void amapLocaitonInit(IMapLocationResultCallBack? locationResultCallBack) { AMapFlutterLocation.updatePrivacyShow(true, true); AMapFlutterLocation.updatePrivacyAgree(true); AMapFlutterLocation.setApiKey("c9856efd6bae11ff6897cffede9af428", ""); ///iOS 获取native精度类型 if (Platform.isIOS) { requestAccuracyAuthorization(); } ///注册定位结果监听 _locationListener = _locationPlugin! .onLocationChanged() .listen((Map<String, Object>? result) { locationResultCallBack!(result); }); }开始定位
///开始定位 void startLocation() async { /// 检查是否开启GSP和定位权限 bool hasLocationPermission = await requestPermission(); if (hasLocationPermission) { _setLocationOption(); _locationPlugin!.startLocation(); } }停止定位
为了让定位不一直执行,当获取到定位数据时可以停止定位
///停止定位 void stopLocation() { _locationPlugin!.stopLocation(); }销毁定位
void amapLocationDispose() { ///移除定位监听 if (null != _locationListener) { _locationListener!.cancel(); } ///销毁定位 if (null != _locationPlugin) { _locationPlugin!.destroy(); } }
/ 定位数据创建MySQL表 /
高德地图定位获取到的数据转换成Json字符串并用创建的.json文件保存起来,方便使用Navicat Preminum 生成表 。
/ 个人位置信息插入、修改 /
创建LocationMapper.xml
里面存放了SQL查询的语句 (插入用户位置信息 、根据userId查询用户位置信息 、修改用户位置信息)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xm.chat.dao.LocationMapper"> <resultMap type="com.xm.chat.entity.admin.Location" id="BaseResultMap"> <result property="callbackTime" column="callbackTime"/> <result property="locationTime" column="locationTime"/> <result property="locationType" column="locationType"/> <result property="latitude" column="latitude"/> <result property="longitude" column="longitude"/> <result property="accuracy" column="accuracy"/> <result property="altitude" column="altitude"/> <result property="bearing" column="bearing"/> <result property="speed" column="speed"/> <result property="country" column="country"/> <result property="province" column="province"/> <result property="city" column="city"/> <result property="district" column="district"/> <result property="street" column="street"/> <result property="streetNumber" column="streetNumber"/> <result property="cityCode" column="cityCode"/> <result property="adCode" column="adCode"/> <result property="address" column="address"/> <result property="description" column="description"/> <result property="user_id" column="user_id"/> </resultMap> <!-- 插入用户位置信息 --> <insert id="editUserLocation" parameterType="com.xm.chat.entity.admin.Location"> insert into tb_location(callbackTime,locationTime,locationType,latitude,longitude,accuracy,altitude, bearing,speed,country,province,city,district,street,streetNumber,cityCode, adCode,address,description,user_id )values(#{callbackTime},#{locationTime},#{locationType} ,#{latitude},#{longitude},#{accuracy},#{altitude},#{bearing}, #{speed},#{country},#{province},#{city},#{district},#{street},#{streetNumber},#{cityCode},#{adCode} ,#{address},#{description},#{user_id}) </insert> <!-- 根据userId查询用户位置信息 --> <select id="selectByUserIdCount" parameterType="String" resultMap="BaseResultMap"> select * from tb_location where user_id = #{user_id} </select> <!-- 修改用户位置信息 --> <update id="updateByUserIdLocation" parameterType="com.xm.chat.entity.admin.Location"> update tb_location set callbackTime=#{callbackTime},locationTime=#{locationTime},locationType=#{locationType} ,latitude=#{latitude},longitude=#{longitude},accuracy=#{accuracy},altitude=#{altitude},bearing=#{bearing}, speed=#{speed},country=#{country},province=#{province},city=#{city},district=#{district},street=#{street},streetNumber=#{streetNumber}, cityCode=#{cityCode},adCode=#{adCode},address=#{address},description=#{description},user_id=#{user_id} where user_id=#{user_id} </update> </mapper>创建LocationService 并实现
package com.xm.chat.service.admin; import com.xm.chat.entity.admin.Intro; import com.xm.chat.entity.admin.Location; public interface LocationService { String editUserLocation(Location location); Location selectByUserIdCount(String userId); String updateByUserIdIntro(Location location); }package com.xm.chat.service.admin.impl; import com.xm.chat.common.ServiceResultEnum; import com.xm.chat.dao.LocationMapper; import com.xm.chat.entity.admin.Location; import com.xm.chat.service.admin.LocationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class LocationServiceImpl implements LocationService { @Autowired private LocationMapper locationMapper; @Override public String editUserLocation(Location location) { if (locationMapper.editUserLocation(location) > 0) { return ServiceResultEnum.SUCCESS.getResult(); } return ServiceResultEnum.DB_ERROR.getResult(); } @Override public Location selectByUserIdCount(String userId) { return locationMapper.selectByUserIdCount(userId); } @Override public String updateByUserIdIntro(Location location) { if (locationMapper.updateByUserIdLocation(location) > 0) { return ServiceResultEnum.SUCCESS.getResult(); } return ServiceResultEnum.DB_ERROR.getResult(); } }创建 LocationMapper
package com.xm.chat.dao; import com.xm.chat.entity.admin.Location; public interface LocationMapper { /** * 编辑用户位置信息 * @param location * @return */ int editUserLocation(Location location); /** * 根据userId查询是否存在用户位置信息 * @param userId * @return */ Location selectByUserIdCount(String userId); /** * 根据userId修改用户位置信息 * @param location * @return */ int updateByUserIdLocation(Location location); }创建LocationController
package com.xm.chat.controller.admin; import com.xm.chat.common.ServiceResultEnum; import com.xm.chat.entity.admin.Location; import com.xm.chat.service.admin.LocationService; import com.xm.chat.util.JwtUtils; import com.xm.chat.util.Result; import com.xm.chat.util.ResultGenerator; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.Objects; @Controller @RequestMapping("/admin") public class LocationController { @Resource LocationService locationService; ///编辑位置信息 @RequestMapping(value = "/edit/location", method = RequestMethod.POST) @ResponseBody public Result editIntro(HttpServletRequest request, @ModelAttribute Location intro) { if (Objects.isNull(intro)) { return ResultGenerator.genFailResult("参数异常!"); } // 用户ID String userId =JwtUtils.getClaimUserId(request); intro.setUser_id(userId); Location locationResult = locationService.selectByUserIdCount(userId); if (locationResult != null) { /// 修改位置信息 String result = locationService.updateByUserIdIntro(intro); if (ServiceResultEnum.SUCCESS.getResult().equals(result)) { return ResultGenerator.genSuccessResult(); } else { return ResultGenerator.genFailResult(result); } } else { /// 插入位置信息 String result = locationService.editUserLocation(intro); if (ServiceResultEnum.SUCCESS.getResult().equals(result)) { return ResultGenerator.genSuccessResult(); } else { return ResultGenerator.genFailResult(result); } } } }模拟请求
/ 附近所有人的位置信息 /
创建 NearPerMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.xm.chat.dao.NearPerMapper"> <resultMap type="com.xm.chat.entity.near.NearPer" id="BaseResultMap"> <result property="intro.id" column="id"/> <result property="intro.head" column="head"/> <result property="intro.nick_name" column="nick_name"/> <result property="intro.city" column="city"/> <result property="intro.birthday" column="birthday"/> <result property="intro.job" column="job"/> <result property="intro.make_fir_pur" column="make_fir_pur"/> <result property="intro.expect" column="expect"/> <result property="intro.wx_account" column="wx_account"/> <result property="intro.is_hide_wx" column="is_hide_wx"/> <result property="intro.height" column="height"/> <result property="intro.weight" column="weight"/> <result property="intro.per_intro" column="per_intro"/> <result property="intro.user_id" column="user_id"/> <result property="action.id" column="id"/> <result property="action.cur_loc" column="cur_loc"/> <result property="action.is_face_rec" column="is_face_rec"/> <result property="action.las_onl_time" column="las_onl_time"/> <result property="action.user_id" column="user_id"/> <result property="faceRec.id" column="id"/> <result property="faceRec.user_id" column="user_id"/> <result property="faceRec.pic" column="pic"/> <result property="faceRec.video" column="video"/> <result property="location.latitude" column="latitude"/> <result property="location.longitude" column="longitude"/> <result property="location.city" column="city"/> <result property="location.locationTime" column="locationTime"/> <result property="location.distance" column="distance"/> </resultMap> <select id="findNerPerList" parameterType="Map" resultMap="BaseResultMap"> select *, round( 6378.138 * 2 * asin( sqrt( pow( sin(( #{latitude} * pi() / 180 - latitude * pi() / 180 ) / 2 ), 2 ) + cos( #{latitude} * pi() / 180) * cos(latitude * pi() / 180) * pow( sin(( #{longitude} * pi() / 180 - longitude * pi() / 180 ) / 2 ), 2 ))) * 1000 ) AS distance FROM (select * from tb_intro <if test="start!=null and limit!=null"> limit #{start},#{limit} </if>) as tbintro left join tb_action on (tbintro.user_id=tb_action.user_id) left join tb_face_rec on (tbintro.user_id=tb_face_rec.user_id) left join tb_location on (tbintro.user_id=tb_location.user_id) ORDER BY distance ASC LIMIT 10 </select> </mapper>根据经纬度计算距离排序、分页
通过当前你所在位置的 经纬度 和其他所有人的 经纬度 进行距离的计算
SELECT *, round( 6378.138 * 2 * asin( sqrt( pow( sin(( 当前你所在位置的纬度 * pi() / 180 - 其他人所在位置的维度 * pi() / 180 ) / 2 ), 2 ) + cos( 当前你所在位置的纬度 * pi() / 180) * cos( 其他人所在位置的维度 * pi() / 180) * pow( sin(( 当前你所在位置的经度 * pi() / 180 - 其他人所在位置的经度 * pi() / 180 ) / 2 ), 2 ))) * 1000 ) AS distance FROM 数据表 ORDER BY distance ASC LIMIT 10;创建 NearPerService 并实现
package com.xm.chat.service.near; import com.xm.chat.util.PageQueryUtil; import com.xm.chat.util.PageResult; public interface NearPerService { /** * 附近 分页 * @param pageUtil * @return */ PageResult getNearPerPage(PageQueryUtil pageUtil); }package com.xm.chat.service.near.impl; import com.xm.chat.dao.NearPerMapper; import com.xm.chat.entity.near.NearPer; import com.xm.chat.service.near.NearPerService; import com.xm.chat.util.PageQueryUtil; import com.xm.chat.util.PageResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class NearPerServiceImpl implements NearPerService { @Autowired private NearPerMapper nearPerMapper; @Override public PageResult getNearPerPage(PageQueryUtil pageUtil) { PageResult pageResult; List<NearPer> nearPers=new ArrayList<>(); int totalCount=0; try { nearPers = nearPerMapper.findNerPerList(pageUtil); }catch (Exception e){ totalCount=0; } pageResult = new PageResult(nearPers, totalCount, pageUtil.getLimit(), pageUtil.getPage()); return pageResult; } }创建NearPerMapper
package com.xm.chat.dao; import com.xm.chat.entity.near.NearPer; import com.xm.chat.util.PageQueryUtil; import java.util.List; public interface NearPerMapper { List<NearPer> findNerPerList(PageQueryUtil pageUtil); }创建 NearController
package com.xm.chat.controller.near; import com.xm.chat.service.near.NearPerService; import com.xm.chat.util.PageQueryUtil; import com.xm.chat.util.Result; import com.xm.chat.util.ResultGenerator; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; import java.util.Map; @Controller @RequestMapping("/admin") public class NearController { @Resource NearPerService nearPerService; @RequestMapping(value = "/nearper/list", method = RequestMethod.POST) @ResponseBody public Result nearPerList(@RequestParam Map<String, Object> params) { if (StringUtils.isEmpty(params.get("page")) || StringUtils.isEmpty(params.get("limit"))) { return ResultGenerator.genFailResult("参数异常!"); } PageQueryUtil pageUtil = new PageQueryUtil(params); return ResultGenerator.genSuccessDataResult(nearPerService.getNearPerPage(pageUtil)); } }运行SpringBoot工程测试接口
{ "resultCode": 200, "message": "SUCCESS", "data": { "totalCount": 0, "pageSize": 10, "totalPage": 0, "currPage": 1, "list": [ { "intro": { "id": 9, "head": "https://1.15.0.115:8081/upload/user51/type_head/20220827_2135548.png", "nick_name": "昵称4", "city": "常驻城市1", "birthday": "生日1", "job": "职业1", "make_fir_pur": "交友目的1", "expect": "期望对象1", "wx_account": "微信1", "is_hide_wx": "是否隐藏微信1", "height": "身高1", "weight": "体重1", "per_intro": "个人介绍1", "user_id": "4" }, "action": { "id": 9, "cur_loc": null, "las_onl_time": null, "is_face_rec": 0, "user_id": "4" }, "faceRec": { "id": 9, "pic": null, "video": null, "user_id": "4" }, "location": { "callbackTime": null, "locationTime": "locationTime", "locationType": null, "latitude": "31.22352", "longitude": "121.45591", "accuracy": null, "altitude": null, "bearing": null, "speed": null, "country": null, "province": null, "city": "常驻城市1", "district": null, "street": null, "streetNumber": null, "cityCode": null, "adCode": null, "address": null, "description": null, "user_id": null, "distance": "29280.0" } }, { "intro": { "id": 10, "head": "https://1.15.0.115:8081/upload/user51/type_head/20220827_2135548.png", "nick_name": "昵称4", "city": "常驻城市1", "birthday": "生日1", "job": "职业1", "make_fir_pur": "交友目的1", "expect": "期望对象1", "wx_account": "微信1", "is_hide_wx": "是否隐藏微信1", "height": "身高1", "weight": "体重1", "per_intro": "个人介绍1", "user_id": "7" }, "action": { "id": 10, "cur_loc": null, "las_onl_time": null, "is_face_rec": 0, "user_id": "7" }, "faceRec": { "id": 10, "pic": null, "video": null, "user_id": "7" }, "location": { "callbackTime": null, "locationTime": "locationTime", "locationType": null, "latitude": "31.03241", "longitude": "121.22654", "accuracy": null, "altitude": null, "bearing": null, "speed": null, "country": null, "province": null, "city": "常驻城市1", "district": null, "street": null, "streetNumber": null, "cityCode": null, "adCode": null, "address": null, "description": null, "user_id": null, "distance": "30950.0" } }, { "intro": { "id": 8, "head": "https://1.15.0.115:8081/upload/user51/type_head/20220827_2135548.png", "nick_name": "昵称3", "city": "常驻城市1", "birthday": "生日1", "job": "职业1", "make_fir_pur": "交友目的1", "expect": "期望对象1", "wx_account": "微信1", "is_hide_wx": "是否隐藏微信1", "height": "身高1", "weight": "体重1", "per_intro": "个人介绍1", "user_id": "3" }, "action": { "id": 8, "cur_loc": null, "las_onl_time": null, "is_face_rec": 0, "user_id": "3" }, "faceRec": { "id": 8, "pic": null, "video": null, "user_id": "3" }, "location": { "callbackTime": null, "locationTime": "locationTime", "locationType": null, "latitude": "36.30744", "longitude": "120.39629", "accuracy": null, "altitude": null, "bearing": null, "speed": null, "country": null, "province": null, "city": "常驻城市1", "district": null, "street": null, "streetNumber": null, "cityCode": null, "adCode": null, "address": null, "description": null, "user_id": null, "distance": "561350.0" } }, { "intro": { "id": 6, "head": "https://1.15.0.115:8081/upload/user51/type_head/20220827_2135548.png", "nick_name": "昵称1", "city": "常驻城市1", "birthday": "生日1", "job": "职业1", "make_fir_pur": "交友目的1", "expect": "期望对象1", "wx_account": "微信1", "is_hide_wx": "是否隐藏微信1", "height": "身高1", "weight": "体重1", "per_intro": "个人介绍1", "user_id": "1" }, "action": { "id": 6, "cur_loc": null, "las_onl_time": null, "is_face_rec": 0, "user_id": "1" }, "faceRec": { "id": 6, "pic": null, "video": null, "user_id": "1" }, "location": { "callbackTime": null, "locationTime": "locationTime", "locationType": null, "latitude": "40.22077", "longitude": "116.23128", "accuracy": null, "altitude": null, "bearing": null, "speed": null, "country": null, "province": null, "city": "常驻城市1", "district": null, "street": null, "streetNumber": null, "cityCode": null, "adCode": null, "address": null, "description": null, "user_id": null, "distance": "1087401.0" } }, { "intro": { "id": 7, "head": "https://1.15.0.115:8081/upload/user51/type_head/20220827_2135548.png", "nick_name": "昵称2", "city": "常驻城市1", "birthday": "生日1", "job": "职业1", "make_fir_pur": "交友目的1", "expect": "期望对象1", "wx_account": "微信1", "is_hide_wx": "是否隐藏微信1", "height": "身高1", "weight": "体重1", "per_intro": "个人介绍1", "user_id": "2" }, "action": { "id": 7, "cur_loc": null, "las_onl_time": null, "is_face_rec": 0, "user_id": "2" }, "faceRec": { "id": 7, "pic": null, "video": null, "user_id": "2" }, "location": { "callbackTime": null, "locationTime": "locationTime", "locationType": null, "latitude": "23.15792", "longitude": "113.27324", "accuracy": null, "altitude": null, "bearing": null, "speed": null, "country": null, "province": null, "city": "常驻城市1", "district": null, "street": null, "streetNumber": null, "cityCode": null, "adCode": null, "address": null, "description": null, "user_id": null, "distance": "1196003.0" } } ] } }
/ 通过app首页展示位置信息列表 /
通过Navicat Priminum 创建 tb_location 表并导出 chatdb.sql 文件, 最后部署到云服务器上 . 将SpringBoot 工程编译成jar包部署到云服务器上 . ( 参考 : Flutter 项目实战 注册接口实现https协议访问(三))
创建 MVP 模式 callback
home_callback.dart
import 'package:flutter_person_course/common/base/model/IModel.dart'; import 'package:flutter_person_course/common/base/presenter/IPresenter.dart'; import 'package:flutter_person_course/common/base/view/IView.dart'; abstract class CHomeModel extends IModel { /// loadHomeData(Map<String, dynamic> p, SuccessCallback s, FailureCallback f); /// 编辑位置信息 editLocationData( Map<String, dynamic> p, SuccessCallback s, FailureCallback f); } abstract class CHomePresenter extends IPresenter { /// loadHomeData(Map<String, dynamic> p); /// 编辑位置信息 editLocationData(Map<String, dynamic> p); } abstract class CHomeView extends IView { showHomeData(dynamic data); showEditLocationData(dynamic data); }创建 Model 层 MHome
class MHome extends AbstractModel implements CHomeModel { @override void dispose() { // TODO: implement dispose HttpManager().cancel(tag!); } @override loadHomeData(Map<String, dynamic> p, s, f) async{ return HttpManager().post( url: '/nearper/list', tag: tag!, successCallback: (data) { s(data); }, errorCallback: (data) { f(data); }, params: p); } @override editLocationData(Map<String, dynamic> p, SuccessCallback s, FailureCallback f) { return HttpManager().post( url: '/edit/location', tag: tag!, successCallback: (data) { s(data); }, errorCallback: (data) { f(data); }, params: p); } }创建Presenter PHome
class PHome extends AbstractPresenter<CHomeView, CHomeModel> implements CHomePresenter { @override IModel createModel() { return MHome(); } @override loadHomeData(Map<String, dynamic> p) { view?.startLoading(); return model?.loadHomeData(p, (data) { view?.showLoadSuccess(); view?.showHomeData(data); model?.dispose(); }, (error) { view?.showLoadFailure(error.code!, error.message!); }); } @override editLocationData(Map<String, dynamic> p) { view?.startLoading(); return model?.editLocationData(p, (data) { view?.showLoadSuccess(); view?.showEditLocationData(data); model?.dispose(); }, (error) { view?.showLoadFailure(error.code!, error.message!); }); } }高德地图获取的位置信息插入云服务数据库中
...... late PHome _pHome; final Map<String, String> _homeMap = <String, String>{}; final GlobalKey<HomeSliverWidgetState> _homeSliverKey = GlobalKey(); @override void initState() { // TODO: implement initState super.initState(); amapLocaitonInit((Map<String, Object>? result) { logV("高德地图定位信息: ${json.encode(result)}"); _pHome.editLocationData(result!); }); _pHome = PHome(); _pHome.attachView(this); _loadHomeData(); } ......I/flutter (23766): AppInfo v 高德地图定位信息: {"callbackTime":"2022-08-29 23:03:12","locationTime":"2022-08-29 23:03:13","locationType":5,"latitude":31.298391,"longitude":121.192297,"accuracy":2 5.0,"altitude":0.0,"bearing":0.0,"speed":0.0,"country":"中国","province":"上海 市","city":"上海市","district":"嘉定区","street":"于塘路","streetNumber":"498 号","cityCode":"021","adCode":"310114","address":"上海市嘉定区于塘路498号靠近顾八 房","description":"在顾八房附近"} I/flutter (23766): AppInfo v 相应数据:{resultCode: 200, message: SUCCESS, data: null}查询云服务数据库数据
展示列表数据
@override Widget build(BuildContext context) { return MediaQuery.removePadding( context: context, removeTop: true, child: GridView.builder( padding: EdgeInsets.all(20.w), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 20.w, mainAxisSpacing: 20.h, childAspectRatio: 0.7), itemCount: _homeDatas.length, itemBuilder: (BuildContext context, int index) { var _homeData = _homeDatas[index]; /// 获取图片宽度 double picWidth = MediaQuery.of(context).size.width / 2 - 30.w; double picHeight = picWidth; return Card( elevation: 0.0, color: Colors.black.withOpacity(0.03), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Container( width: picWidth, height: picHeight, color: Colors.green.withOpacity(0.2), padding: EdgeInsets.all(60.w), child: CachedNetworkImage( imageUrl: '${_homeData['intro']['head']}', fit: BoxFit.fitWidth, cacheManager: EsoImageCacheManager(), errorWidget: (context, url, error) { return const Icon( Icons.error, ); }), ), flex: 1, ), Padding( child: Text( '\t${_homeData['intro']['nick_name']}\t', style: TextStyle( fontSize: 40.sp, color: Colors.blue.withOpacity(0.7), fontWeight: FontWeight.bold), ), padding: EdgeInsets.all(16.w), ), Container( padding: EdgeInsets.only( left: 20.w, right: 20.w, top: 10.h, bottom: 10.h), margin: EdgeInsets.only( left: 16.w, right: 16.w, bottom: 16.w), child: Text( '${_homeData['location']['distance']} 米', style: TextStyle( fontSize: 40.sp, color: Colors.red.withOpacity(0.6)), textAlign: TextAlign.start, ), alignment: Alignment.centerLeft, decoration: BoxDecoration( color: Colors.black12.withOpacity(0.08), borderRadius: BorderRadius.all(Radius.circular(50.w)))), ], ), ); }), ); }
![]()
更多推荐
























所有评论(0)