<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Flutter on Colinx Blog</title><link>/tags/flutter/</link><description>Recent content in Flutter on Colinx Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Tue, 30 Mar 2021 00:00:00 +0000</lastBuildDate><atom:link href="/tags/flutter/index.xml" rel="self" type="application/rss+xml"/><item><title>Flutter 拖动排序列表与跨平台优化实践</title><link>/posts/flutter-%E6%8B%96%E5%8A%A8%E6%8E%92%E5%BA%8F%E5%88%97%E8%A1%A8%E4%B8%8E%E8%B7%A8%E5%B9%B3%E5%8F%B0%E4%BC%98%E5%8C%96%E5%AE%9E%E8%B7%B5/</link><pubDate>Tue, 30 Mar 2021 00:00:00 +0000</pubDate><guid>/posts/flutter-%E6%8B%96%E5%8A%A8%E6%8E%92%E5%BA%8F%E5%88%97%E8%A1%A8%E4%B8%8E%E8%B7%A8%E5%B9%B3%E5%8F%B0%E4%BC%98%E5%8C%96%E5%AE%9E%E8%B7%B5/</guid><description>
&lt;!-- # Flutter 拖动排序列表与跨平台优化实践 -->
&lt;p>Flutter 中实现拖动排序的列表非常简单，使用官方的&lt;code>ReorderableListView&lt;/code>替代原本的&lt;code>ListView&lt;/code>即可，&lt;code>ListView.builder&lt;/code>同理。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-dart" data-lang="dart"> &lt;span style="color:#66d9ef">return&lt;/span> ReorderableListView(
&lt;span style="color:#75715e">// padding: const EdgeInsets.symmetric(horizontal: 40),
&lt;/span>&lt;span style="color:#75715e">&lt;/span> children: &lt;span style="color:#f92672">&amp;lt;&lt;/span>Widget&lt;span style="color:#f92672">&amp;gt;&lt;/span>[
&lt;span style="color:#66d9ef">for&lt;/span> (&lt;span style="color:#66d9ef">int&lt;/span> index &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; index &lt;span style="color:#f92672">&amp;lt;&lt;/span> _items.length; index&lt;span style="color:#f92672">++&lt;/span>)
ListTile(
key: Key(&lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#e6db74">$&lt;/span>index&lt;span style="color:#e6db74">&amp;#39;&lt;/span>),
tileColor: _items[index].isOdd &lt;span style="color:#f92672">?&lt;/span> oddItemColor &lt;span style="color:#f92672">:&lt;/span> evenItemColor,
title: Text(&lt;span style="color:#e6db74">&amp;#39;Item &lt;/span>&lt;span style="color:#e6db74">${&lt;/span>_items[index]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>),
),
],
onReorder: (&lt;span style="color:#66d9ef">int&lt;/span> oldIndex, &lt;span style="color:#66d9ef">int&lt;/span> newIndex) {
setState(() {
&lt;span style="color:#66d9ef">if&lt;/span> (oldIndex &lt;span style="color:#f92672">&amp;lt;&lt;/span> newIndex) {
newIndex &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
}
&lt;span style="color:#66d9ef">final&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> item &lt;span style="color:#f92672">=&lt;/span> _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
);
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面是官方给的 demo，简洁明了。&lt;a href="https://www.youtube.com/watch?v=yll3SNXvQCw">官方介绍视频&lt;/a>下面的评论里，人家直呼比原生 Android 写的过瘾的多。阅读文档后我给我的 App 的界面也加上了可拖动排序的功能。效果如下图&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/20210330234001.png" alt="截屏 2021-03-30 23.04.59">&lt;/p>
&lt;p>虽然可以实现拖动了，但是右边有一个按钮很碍眼。不过这个是用来控制拖动的，鼠标移上去才能触发拖动。&lt;/p>
&lt;p>翻了翻文档发现，这个地方&lt;code>ReorderableListView&lt;/code>在移动端和桌面端的处理是不一样的，上图（桌面 macos）右边会出现一个 dragHandler，而移动端则是靠长按列表项触发拖动。&lt;/p>
&lt;p>要把这个碍眼的图标去掉，有两个方案：&lt;/p>
&lt;ul>
&lt;li>找到定义这个图标的地方，更换一个合适的图标，并在外面包裹一层，仅在鼠标 hover 时将图标显示以进行拖动，其他情况下隐藏&lt;/li>
&lt;li>将拖动的实现定义为和移动端相同，即都通过长按列表项触发拖动&lt;/li>
&lt;/ul>
&lt;p>针对方案一，以&lt;code>ReorderableListView&lt;/code> 和&lt;code>Icon&lt;/code>为关键词搜索，很遗憾的是并没有这方面的资料，又翻了翻源码，并没有找到可以自定义右边这个拖拽按钮的实现。&lt;/p>
&lt;p>在 Flutter 官方的 Github 仓库的 issue 中，&lt;a href="https://github.com/flutter/flutter/issues/66080#issuecomment-771123430">https://github.com/flutter/flutter/issues/66080#issuecomment-771123430&lt;/a> 对相关问题做了阐述，并有提案对&lt;code>ReorderableListView&lt;/code>进行了改进。该 issue 对应的 pr 已经被合并到 stable channel，查阅相关 API 后了解到可以使用&lt;code>buildDefaultDragHandles: false&lt;/code>，关闭默认的拖拽触发实现，再使用&lt;code>ReorderableDelayedDragStartListener&lt;/code>包裹原先的&lt;code>ListTile&lt;/code>即可实现桌面端和移动端都通过长按列表项触发拖拽排序。&lt;/p>
&lt;p>不过相应的，ListTile 的&lt;code>onLongPress&lt;/code>就不能再有响应了。刚好今天完成了滑动删除的实现，现在列表也的删除、排序已经高度可用且多平台统一了。&lt;/p>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/20210330233350.png" alt="截屏 2021-03-30 23.21.32">&lt;/p>
&lt;p>附相关代码实现：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-dart" data-lang="dart">body: ReorderableListView.builder(
buildDefaultDragHandles: &lt;span style="color:#66d9ef">false&lt;/span>,
onReorder: (&lt;span style="color:#66d9ef">int&lt;/span> oldIndex, &lt;span style="color:#66d9ef">int&lt;/span> newIndex) {
setState(() {
&lt;span style="color:#66d9ef">if&lt;/span> (oldIndex &lt;span style="color:#f92672">&amp;lt;&lt;/span> newIndex) newIndex &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;span style="color:#66d9ef">var&lt;/span> temp &lt;span style="color:#f92672">=&lt;/span> l.removeAt(oldIndex);
l.insert(newIndex, temp);
});
},
itemCount: l.length,
itemBuilder: (context, index) {
&lt;span style="color:#66d9ef">final&lt;/span> item &lt;span style="color:#f92672">=&lt;/span> l[index];
&lt;span style="color:#66d9ef">return&lt;/span> Dismissible(
key: item.key,
background: listTileBackground(),
onDismissed: (direction) {
setState(() {
lastDeleted &lt;span style="color:#f92672">=&lt;/span> item;
l.removeAt(index);
});
ScaffoldMessenger.of(context).showSnackBar(msgDeleted);
},
child: ReorderableDelayedDragStartListener(
key: item.key,
index: index,
child: ListTile(
title: Text(item.title),
subtitle: Text(item.content),
contentPadding: EdgeInsets.fromLTRB(&lt;span style="color:#ae81ff">16&lt;/span>, &lt;span style="color:#ae81ff">8&lt;/span>, &lt;span style="color:#ae81ff">16&lt;/span>, &lt;span style="color:#ae81ff">8&lt;/span>),
onTap: () {
&lt;span style="color:#75715e">//your function here
&lt;/span>&lt;span style="color:#75715e">&lt;/span> },
&lt;span style="color:#75715e">// onLongPress: () {
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#75715e">// lastDeleted = item;
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#75715e">// l.removeAt(index);
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#75715e">// setState(() {});
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#75715e">// ScaffoldMessenger.of(context)
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#75715e">// .showSnackBar(msgDeleted);
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#75715e">// },
&lt;/span>&lt;span style="color:#75715e">&lt;/span> )));
})));
&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Colin's 实验室 - 2021 春</title><link>/posts/colins-%E5%AE%9E%E9%AA%8C%E5%AE%A4-2021%E6%98%A5/</link><pubDate>Thu, 25 Feb 2021 00:00:00 +0000</pubDate><guid>/posts/colins-%E5%AE%9E%E9%AA%8C%E5%AE%A4-2021%E6%98%A5/</guid><description>
&lt;!-- # Colin's 实验室 - 2021 春 -->
&lt;blockquote>
&lt;p>小玩具及他们的 demo&lt;/p>
&lt;/blockquote>
&lt;h2 id="英语文本智能查词project-sweeper">
英语文本智能查词（Project Sweeper）
&lt;a href="#%e8%8b%b1%e8%af%ad%e6%96%87%e6%9c%ac%e6%99%ba%e8%83%bd%e6%9f%a5%e8%af%8dproject-sweeper" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>自动分割给定的英文文本，提取词元后在数据库中搜索，根据给定的词汇量和难度等级进行筛选，只能提取阅读障碍词汇并高亮当前备考项目（如四级）的重点单词&lt;/p>
&lt;/blockquote>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/20210330233722.jpg" alt="360 截图 20210206210445677">&lt;/p>
&lt;h2 id="知乎爬虫及-js-逆向">
知乎爬虫及 JS 逆向
&lt;a href="#%e7%9f%a5%e4%b9%8e%e7%88%ac%e8%99%ab%e5%8f%8a-js-%e9%80%86%e5%90%91" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>日常用 RSS 订阅知乎的一些高质量专栏。但由于知乎本事并不支持 RSS，内容大多通过 RSShub 来的，其本质是个爬虫，经常会受到前端页面结构变更的影响。为了应对这个变化，RSShub 中对于知乎相关页面的爬取规则必须得重写。&lt;/p>
&lt;p>分析了一通知乎的页面，发现有个接口可以直接请求，但是会检验 header。header 里面有几项特殊的自定义参数，&lt;code>x-zse-83&lt;/code> 和 &lt;code>x-zse-86&lt;/code>等。为了搞清楚这里面的数值怎么来的，就必须对知乎前端页面资源中的一个 js 文件进行逆向分析。&lt;/p>
&lt;p>逆向折腾了大半天，就快要成功提取核心加密函数的时候，发现知乎的前端页面为了 SEO 有加入一页的文章列表数据，可以直接用上。考虑到逆向的工作量和潜在的法律问题，遂放弃原本的方案。&lt;/p>
&lt;p>新的方案完成后，已向 RSShub 提交 PR 并已被合并。&lt;/p>
&lt;/blockquote>
&lt;h2 id="mc-服务器搭建与极限优化">
MC 服务器搭建与极限优化
&lt;a href="#mc-%e6%9c%8d%e5%8a%a1%e5%99%a8%e6%90%ad%e5%bb%ba%e4%b8%8e%e6%9e%81%e9%99%90%e4%bc%98%e5%8c%96" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>1 核 2G 学生机，从 2 人联机频频崩溃到 8 人挖矿毫无压力，学习了 JVM GC 种种，对服务端程序的一些参数也渐渐熟悉。优化效果喜人，总有还能压榨的性能，就像资本家看手下的骡子一样 hhh&lt;/p>
&lt;/blockquote>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs20210207205949.png" alt="屏幕截图 (12)">&lt;/p>
&lt;h2 id="洞洞板冰箱贴cvpro没想好名字">
洞洞板/冰箱贴/CVPRO/（&amp;hellip;没想好名字）
&lt;a href="#%e6%b4%9e%e6%b4%9e%e6%9d%bf%e5%86%b0%e7%ae%b1%e8%b4%b4cvpro%e6%b2%a1%e6%83%b3%e5%a5%bd%e5%90%8d%e5%ad%97" class="h-anchor" aria-hidden="true">#&lt;/a>
&lt;/h2>
&lt;blockquote>
&lt;p>一款跨平台的灵感素材收集与简易管理 App，基于 Flutter 构建，跨平台，颜值在线。&lt;/p>
&lt;/blockquote>
&lt;p>&lt;img src="https://blog-1301127393.file.myqcloud.com/BlogImgs/20210330233350.png" alt="截屏 2021-03-30 23.21.32">&lt;/p>
&lt;blockquote>
&lt;p>持续开发中，附 roadmap&lt;/p>
&lt;p>version 1.0&lt;/p>
&lt;p>[x] Text support&lt;br>
[x] Key shortcut support&lt;br>
[x] About Page&lt;br>
[ ] Content editing&lt;br>
[x] List item dismiss
[x] List Sorting&lt;/p>
&lt;p>Future - Key functions&lt;/p>
&lt;p>[ ] Data Storage&lt;br>
[ ] Pic support&lt;br>
[ ] Trashbin&lt;br>
[ ] File support&lt;br>
[ ] Multiple List&lt;/p>
&lt;p>Future - Key features&lt;/p>
&lt;p>[ ] Grid view&lt;br>
[ ] Drag and Drop support&lt;br>
[ ] Card resize&lt;/p>
&lt;p>Future - Extra&lt;/p>
&lt;p>[ ] Text reformat, delete useless spaces etc.&lt;br>
[ ] Pic OCR support&lt;br>
[ ] WebDav support and automatically upload files&amp;lt;10M&lt;/p>
&lt;/blockquote></description></item></channel></rss>