Flutter中ListView的onTap方法索引计算逻辑疑问
核心原因是闭包捕获变量的特性,结合Flutter列表项的构建逻辑就能明白:
列表项的构建时机
ListView.builder的itemBuilder是在列表项首次渲染到屏幕上时执行的,不是你点击的时候。当itemBuilder处理某个位置的i时,会立刻计算出index = i ~/ 2,同时判断alreadySaved的状态,然后创建对应的ListTile组件——包括它的onTap回调函数。闭包保存了变量的当前值
onTap是一个闭包函数,它会“捕获”创建它时所在作用域的index和alreadySaved变量的当前值。也就是说,当itemBuilder为第0个列表项(i=0,index=0)创建ListTile时,这个ListTile的onTap就记住了index=0;为第2个位置(i=2,index=1)创建ListTile时,onTap就记住了index=1,以此类推。调试时的误解澄清
你看到的“onTap先触发,ListView.builder后执行”,其实是指点击后触发setState导致的重新build流程,但当前被点击的那个列表项的widget,早就在上一次build中被itemBuilder创建好了,onTap里的index是创建时就确定的,完全不需要在点击时再去执行itemBuilder计算。setState后的更新逻辑
当你点击触发setState后,Flutter会重新执行build方法,ListView.builder会再次调用itemBuilder,为需要更新的列表项重新计算index、alreadySaved,生成新的onTap回调——这保证了后续的点击依然能对应到最新的列表数据。
举个简单例子:假设首次build时,itemBuilder处理i=0,index=0,此时_suggestions里第一个元素是"abc",onTap就记住了要操作_suggestions[0]也就是"abc"。哪怕之后_suggestions新增了数据,你点击这个旧的列表项时,onTap里的index还是0,依然会正确操作最初的那个"abc"。
内容的提问来源于stack exchange,提问作者karthikeyan

