第一百一十四回 局部动态列表


我们在上一章回中介绍了dart语言中的 setter/getter相关的内容,本章回中将介绍 局部动态列表.闲话休提,让我们一起Talk Flutter吧。

概念介绍

在正常情况下列表位于整个页面中,而且可以在整个页面中滚动,我们在这里说的局部动态列表是指在页面中的某一部分区域中显示一个列表,列表的滚动范围只限于这个局部区域,我们把这样的列表叫作局部动态列表。在实际项目中这样的场景比较多,本章回中将详细介绍如何实现局部动态列表。

实现方法

我们首先使用使用Column组件划分布局,然后把ListView当作该组件的子组件,这样就创建好了局部动态列表。

这个步骤看着简单,不过还有一些细节需要说明,不然这样的程序会有编译错误:Failed assertion: line 1966 pos 12: 'hasSize。其在原因是Column要求子组件有固定的大小,而子组件ListView没有固定的大小。解决方法有两个,详细如下:

  • 在ListView外面嵌套一个容器组件,比如Container,并且指定容器的高度,相当于间接指定了ListView的高度。
  • 使用shrinkWrap属性,该属性默认值为false.将它设置为true.表示让ListView拥有一个可扩展的最大值。相当于指定了ListView的高度。

上面的两种方法都可以,不过还有一些细节需要解释,详细如下:

  • 在使用第一种方法时还有一些特殊情况需要注意,为了显示ListView中更多的内容,把它外层嵌套的容器高度放大一些,这样做会有超过屏幕高度的风险,此时可以容器的外层再嵌套一个可滚动的组件,比如SingleChildScrollView,这样即使显示的内容超过屏幕了也可以滚动显示。
  • 在使用第二个方法时,主要是不好理解shrinkWrap属性的功能,大家可以查看源代码中的注释,这个注释写的比较清楚,详细如下:
  /// {@template flutter.widgets.scroll_view.shrinkWrap}
  /// Whether the extent of the scroll view in the [scrollDirection] should be
  /// determined by the contents being viewed.
  ///
  /// If the scroll view does not shrink wrap, then the scroll view will expand
  /// to the maximum allowed size in the [scrollDirection]. If the scroll view
  /// has unbounded constraints in the [scrollDirection], then [shrinkWrap] must
  /// be true.
  ///
  /// Shrink wrapping the content of the scroll view is significantly more
  /// expensive than expanding to the maximum allowed size because the content
  /// can expand and contract during scrolling, which means the size of the
  /// scroll view needs to be recomputed whenever the scroll position changes.
  ///
  /// Defaults to false.
  ///
  /// {@youtube 560 315 https://www.youtube.com/watch?v=LUqDNnv_dh0}
  /// {@endtemplate}
  final bool shrinkWrap;

示例代码

介绍完局部动态列表的实现方法后,我们通完示例代码来演示,详细如下:

Column(
  children: [
    const Image(
      width: double.infinity,
      height: 200,
      image: AssetImage("images/ex.png"),
      fit:BoxFit.fill, ),
    const Text('data sample'),
    Container(
      decoration:BoxDecoration(
        color: Colors.green,
        borderRadius: BorderRadius.circular(8)) ,
      height: 200,
      child: ListView.builder(
        ///column中嵌套ListView会报hassize类型的的错误,即使指定list数量也不行
        ///Failed assertion: line 1966 pos 12: 'hasSize
        ///解决方法1:在ListView外层嵌套一个容器,指定容器大小来限定ListView的大小。
        ///该方法相当于创建了个局部List,容器内的List可以自由滚动,也可以通过physics属性让它不滚动
        ///解决方法2:使用shrinkWrap属性,
        itemCount: 10,
        // physics: const NeverScrollableScrollPhysics(),
        itemBuilder: (context,index){
        return const Card(
          child: Padding(
            padding: EdgeInsets.all(10),
            child: Text("List item"),
          ),
        );
          },),
    ),
    Container(
      color: Colors.lightBlue,
      child: ListView.builder(
        ///用来控制List内部的边距,包含head和tail,如果去掉head和tail可以使用only方法
        padding: const EdgeInsets.all(10),
        shrinkWrap: true,
        physics: const NeverScrollableScrollPhysics(),
        itemCount: 20,
        itemBuilder:(context,index){
          return const Card(
            color: Colors.orange,
            child: Padding(
              ///这个padding可以控制card的大小,也就是listItem的大小
              padding: EdgeInsets.all(8),
              child: Text('Another List Item'),
            ),
          );
        },),
    ),
  ],
),

上面的示例代码中通过两个ListView演示了两种解决方法,大家可以去掉外层的容器,或者修改shrikWrap属性值来看看程序出错时的样子,然后按照我们介绍的方法来解决错误,这样做的效果比较好,建议大家自己动手去实践。

看官们,关于"局部动态列表"相关的内容就介绍到这里,欢迎大家在评论区交流与讨论!

<think>我们正在处理一个代码重构任务:将函数'A_star'定义后的所有语句移动到第一局部函数定义之前。假设代码结构如下(伪代码):函数定义1:deffunction1(...):...#我们想将以下'A_star'函数定义后的所有语句移动到第一局部函数定义之前函数定义2:defA_star(...):...语句1语句2...函数定义3:deflocal_function1(...):#这是第一局部函数(在全局层面,函数定义也是语句,但这里我们关注的是可执行语句)...其他函数定义和语句...我们的目标是将从语句1开始直到函数定义3之前的所有语句(即'A_star'函数定义后的非函数定义语句)移动到第一局部函数(即local_function1)定义之前。注意:函数定义本身也是语句,但我们通常把函数定义视为一个整体。这里,用户要求将可执行语句(即非函数定义的语句)移动到第一局部函数定义之前。然而,根据问题描述,我们只移动函数定义后的非函数定义语句(即那些可执行语句),而不移动其他函数定义(除非特别指出)。但是,注意问题中的表述:“将'A_star'函数定义后的所有语句移动到第一局部函数定义之前”。这里“所有语句”可能包括函数定义,也可能不包括?但是,通常我们不会把函数定义移动到另一个函数定义内部(因为局部函数通常是在全局作用域定义的)。因此,我们需要明确:-第一局部函数定义指的是在全局作用域中,在A_star函数定义之后出现的第一个函数定义(我们称之为local_function1)。-而我们要移动的是A_star函数定义之后,直到这个第一局部函数定义之前的那些非函数定义的语句(即可执行语句,比如赋值、循环等)?还是包括函数定义?然而,问题中说的是“语句”,在Python中函数定义也是语句(def语句)。所以这里有两种可能:1.只移动非函数定义的语句(即可执行语句),而不移动其他函数定义。2.移动所有语句(包括函数定义)到第一局部函数定义之前。但是,问题中特别指出“使其定义后的所有内容出现在第一局部函数定义之前”,而且用户提到“所有语句”。另外,在上下文中,我们注意到引用[3]提到了封装和抽象,所以可能涉及到代码结构的组织。为了明确,我们假设用户希望将A_star函数定义之后的所有的代码(包括其他函数定义和可执行语句)都移动到第一局部函数(在A_star之后出现的第一个函数)的前面。这样,A_star函数定义后面就没有任何代码了,而原来在A_star之后第一局部函数之前的所有代码(包括其他函数定义)都被移到了第一局部函数的前面。但是,如果这样,那么第一局部函数定义之前就会包含多个函数定义(包括A_star和其他被移动的函数)以及可执行语句。然后,第一局部函数定义的位置就改变了。然而,问题中说的是“第一局部函数定义”,所以如果我们把其他函数定义移到了它前面,那么它可能就不再是第一个了?所以我们需要重新理解“局部函数”的含义。我们重新解读用户的问题:用户想将A_star函数定义后的所有语句(即A_star函数定义之后,一直到文件末尾的所有语句,或者直到遇到某个局部函数定义之前?)移动到“第一局部函数定义”之前。这里,“第一局部函数定义”指的是在整个文件中,在A_star函数定义之前已经定义的那个函数(即用户提到的第一局部函数)?还是A_star函数定义之后出现的第一个函数?从问题描述看,用户说“移动到第一局部函数定义之前”,同时问题中提到了“第一局部函数”,所以这个第一局部函数应该是在A_star之前就已经定义了的。因为如果是在A_star之后定义的,那么移动后它就会变成在第一局部函数之后(因为移动的代码会放在这个函数之前),这样逻辑就混乱了。但是,用户的问题描述是:“我想将'A_star'函数定义后的所有语句移动到第一局部函数定义之前”。这句话意味着:-第一局部函数定义的位置是在A_star函数定义之前就已经存在的。因此,调整步骤应该是:1.定位到第一局部函数定义的位置(假设它在A_star函数定义之前就已经存在)。2.将A_star函数定义之后的所有语句(即从A_star函数定义的下一个语句开始直到文件末尾)整体移动到第一局部函数定义之前(即在第一局部函数定义的代码之前插入这些语句)。但这样做可能会打乱代码的执行顺序(因为可执行语句的位置变化了),所以需要谨慎。然而,另一种可能是:用户想要调整的是函数定义在代码文本中的位置,而不关心执行顺序(因为函数定义在未调用前不会执行)。也就是说,用户希望将A_star函数定义后的所有内容(包括其他函数和语句)都移动到第一局部函数(这个函数定义在A_star之前)的代码文本之前。但是,这通常是不可能的,因为第一局部函数定义已经在A_star之前了,我们怎么能把A_star后面的东西放到第一局部函数之前?那样就放到了A_star函数定义之前了?所以我们需要重新审视问题:可能是用户写代码时,在A_star函数定义之后写了一些语句,然后他又定义了一个局部函数(比如helperfunction),但是他现在希望这些语句在局部函数定义之前运行?但是这些语句可能依赖于后面的函数?这很混乱。实际上,更合理的解释是:在代码中,有多个函数定义,其中A_star是一个函数定义,然后后面跟着一些可执行语句(可能是主程序)和一些其他函数定义(包括局部函数)。用户希望将这些可执行语句(不包括后面的函数定义)移动到第一局部函数定义之前(即移动到在A_star之后定义的那些函数之前)。这样,这些可执行语句就会在第一局部函数定义之前运行。所以,我们假设代码结构为:deffirst_local_function():#这可能是第一局部函数,但它在A_star之前定义?还是之后定义?passdefA_star():pass#以下是我们要移动的语句(A_star函数定义后的语句)statement1statement2defanother_function():#在A_star之后定义的函数,可能是用户所指的第一局部函数(在A_star之后)?passdefyet_another_function():pass但用户说“第一局部函数定义”,那么这个“第一个”指的是整个代码中的第一个函数定义,还是A_star之后出现的第一个函数定义?根据问题描述,用户说“第一局部函数定义”,并且是在将A_star函数定义后的内容移动到它之前。所以这个“第一局部函数”应该是在A_star之前就已经定义了。否则,如果它是在A_star之后定义的,那么我们要移动的语句就包括它(因为它在A_star之后),然后移动到它之前?这样就会形成一个循环:我们移动的代码块中包含了这个函数定义,然后又要将这个代码块移动到这个函数定义之前,这是不可能的。因此,我们确定:第一局部函数是在A_star函数定义之前就已经定义了的。那么,调整步骤:1.找到第一局部函数定义(在A_star函数定义之前)。2.选中A_star函数定义之后的所有语句(即从A_star函数定义的下一个语句开始直到文件末尾)。3.将这些语句剪切,并粘贴到第一局部函数定义之前(即整个代码的最前面?不,是在第一局部函数定义之前,但第一局部函数定义之前可能还有其他代码,所以我们要插入到第一局部函数定义这个位置的前面)。注意:移动代码后,代码的执行顺序会改变。但是,函数定义只是被定义,只有被调用时才会执行,所以如果移动的代码块中包含函数定义,那么只是改变了这些函数定义的先后顺序。但是,如果移动的代码块中包含可执行语句(例如在全局作用域中的语句),那么这些语句的执行时间就会提前到第一局部函数定义之前(即程序一开始就会执行)。然而,用户的要求可能只是代码结构上的调整,并不考虑执行逻辑?或者用户就是要改变执行顺序?由于问题描述不完整,我们无法得知。所以,我们只能按照文本位置调整。操作步骤(手动调整代码):1.确定第一局部函数定义的位置(假设函数名为first_local_function,且它定义在A_star之前)。2.将A_star函数定义之后的所有内容(从A_star的def语句的下一个语句开始到文件末尾)全部选中(包括后面的函数定义和可执行语句)。3.剪切选中的内容。4.将光标定位到第一局部函数定义的def语句的前面(即在第一局部函数定义之前插入)。5.粘贴。但是,这样就会把整个A_star函数定义之后的内容都移动到第一局部函数定义之前,包括A_star函数之后定义的其他函数和可执行语句。注意:这样也会将A_star函数定义本身移动到第一局部函数定义之前?但用户只要求移动A_star函数定义之后的所有语句,所以A_star函数定义本身不动。因此,正确步骤是:1.定位A_star函数定义的位置:假设我们找到这样的代码段:...(前面的代码,包括第一局部函数定义等)defA_star(...):...(函数体)#以下是A_star函数定义之后的语句statement1statement2...deflocal_function1(...):#这个函数定义是A_star之后第一个出现的函数定义(即用户所说的第一局部函数?但用户要求移动到第一局部函数定义之前,这个局部函数是在A_star之前定义的吗?如果是在A_star之前定义的,那么它已经在前面了,我们就不能在后面找到它?所以这里我们重新考虑)由于问题描述不清,我们换一个角度:用户可能是将代码写在全局作用域中,并且有多个函数定义。用户定义了一个函数A_star,在A_star之后,他写了一些语句,然后他又定义了一个局部函数(在全局作用域中定义,但通常在面向对象的编程中称为局部函数可能指的是嵌套函数?但这里没有嵌套)。所以,这里“局部函数”可能是指在全局作用域中定义的函数(相对于内置函数而言)?那么第一局部函数定义就是整个代码中的第一个函数定义。但是,用户的要求是将A_star函数定义后的所有语句移动到第一局部函数定义之前。如果第一局部函数定义是在整个文件开头,那么移动后,A_star函数定义后的语句就会出现在整个文件的最前面(在第一局部函数定义之前)?这样可能会因为未定义函数或变量而出错。因此,我们假设用户希望调整的代码结构是:deffirst_local_function():...#其他函数定义...defA_star():...#要移动的语句:包括一些可执行语句和可能的其他函数定义print("Hello")#可执行语句defhelper():#用户可能认为这个函数是局部函数?但是它在全局作用域定义...#用户希望将A_star函数定义之后的所有语句(包括可执行语句和helper函数定义)移动到first_local_function之前。移动后,代码变成:#将移动的语句放在这里print("Hello")defhelper():...deffirst_local_function():...#其他函数定义...defA_star():...这样,当程序一开始运行时,就会执行print("Hello"),并且定义了helper函数,然后再定义first_local_function等。注意,执行print时,后面的函数都还没定义,但函数定义是编译时处理的,所以实际上在运行时,函数定义已经提前处理了(在Python中,函数定义也是可执行语句,但通常在模块导入时执行)。所以,在同一个模块中,前面的函数调用后面的函数是允许的,因为当调用发生时,后面的函数已经定义了。但是,如果将可执行语句(如print)放在最前面,那么当执行print时,它后面的函数(如helper)确实还没有定义(因为我们在它前面插入了打印语句,然后定义helper,然后定义first_local_function,但在打印时helper函数定义语句还没执行)。所以,如果打印语句中使用了helper函数,就会出错。因此,移动代码可能会破坏程序逻辑。鉴于问题描述模糊,我们给出一个通用的代码调整建议:如果用户只是想调整代码文本顺序(而不考虑执行顺序),那么可以:Step1:找到第一局部函数定义的起始位置(行号),记为L1(在A_star函数定义之前,并且是用户指定的第一局部函数)。Step2:选中从A_star函数定义结束后的第一个语句开始,直到文件末尾的所有内容,剪切。Step3:将光标定位到第一局部函数定义的前一行(即L1行之前),然后粘贴。例如:原始代码(行号):1:deffirst_local_function():2:...3:4:defA_star():5:...#A_star函数体6:7:#这里是A_star之后的内容8:print("AfterA_star")9:10:defhelper():11:...移动后的代码:1:deffirst_local_function():2:...3:4:#这里插入了从第7行开始到第11行的内容7:print("AfterA_star")10:defhelper():11:...//注意:这里第4行后面原本是A_star函数定义,现在需要保留A_star函数定义在第4行,但移动了它之后的语句但是等等,我们并没有移动A_star函数定义,我们移动的是A_star函数定义之后的内容(从第7行开始)。所以移动后,代码变成:1:deffirst_local_function():2:...3:7:print("AfterA_star")8:10:defhelper():11:...4:defA_star():#注意:现在A_star函数定义跑到后面去了!5:...这显然不是用户想要的,因为用户说只移动A_star函数定义之后的语句,但保留A_star函数定义在原地。所以,我们只移动A_star函数定义之后的语句,而A_star函数定义本身不移动。但是,我们移动的位置是第一局部函数定义之前,而第一局部函数定义在A_star之前,所以移动后,A_star函数定义仍然在第一局部函数定义之后?是的。移动后:1:deffirst_local_function():2:...3:7:print("AfterA_star")//移动到这里的语句8:10:defhelper():11:...4:defA_star():#但是第4行的A_star函数定义现在被移动的代码覆盖了吗?实际上我们是将第7行到文件末尾的内容插到第3行和第4行之间,所以:1:deffirst_local_function():2:...3://插入的代码开始7:print("AfterA_star")8:10:defhelper():11:...//插入的代码结束//然后原来的第4行(即A_star函数定义)仍然在这里4:defA_star():5:...但这样,A_star函数定义还在那里,而它之后的语句(第7行及之后)被移走了,那么A_star函数定义之后就没有语句了?然后我们在第4行A_star函数定义之后,就是文件结束了?不,原始的第7行及以后的内容已经被剪走了。所以,实际上的操作是:1.在原始代码中,我们想要移动的是A_star函数定义(第4-5行)之后的语句(第7行到结束)。2.然后将这些语句插入到第一局部函数定义(第1-2行)的后面(即第2行和第3行之间?这里第3行是空白行)。移动后的代码结构:deffirst_local_function():...[插入的代码]#包括print和helper函数定义print("AfterA_star")defhelper():...defA_star():...#原A_star函数定义之后的内容(已被移动),所以这里就没有了这样,A_star函数定义就成了最后定义的一个函数。因此,总结操作步骤(使用编辑器):1.在编辑器中,选中从A_star函数定义的下一个语句开始直到文件末尾的所有代码。2.剪切。3.找到第一局部函数定义的结束位置(即该函数的最后一行),将光标定位到该函数的下一行(或第一局部函数定义的后面的空白行)。4.粘贴。这样,A_star函数定义后的所有语句都被移动到第一局部函数定义之后了,但也我们要求是“之前”?用户要求的是“之前”。用户要求移动到第一局部函数定义“之前”,所以我们不能放在第一局部函数定义的后面。我们可能误解了用户所说的“之前”和“之后”在代码文本中的位置。在文本编辑器中,代码是从上到下阅读的,上面的代码在“前”,下面的代码在“后”。用户要求移动到第一局部函数定义之前,也就是要放在第一局部函数定义的上方。所以:1.选中要移动的语句(A_star函数定义之后的语句)。2.剪切。3.把光标定位到第一局部函数定义的第一行(包括该行)的前面(即在第一局部函数定义这一行的前面插入一行?然后放在它上面)。4.粘贴。例如:original:1:deffirst_local_function():#第一局部函数定义2:......#可能有其他代码10:defA_star():11:...12:#endofA_star13:print("AfterA_star")#要移动的语句114:defhelper():#要移动的语句2(函数定义)15:...移动后:我们把第13行到第15行剪切,然后粘贴到第1行的前面(即放在第一局部函数定义之前)移动后的代码:13:print("AfterA_star")#被移动的语句14:defhelper():#被移动的函数定义15:...1:deffirst_local_function():2:......#其他代码10:defA_star():11:...这样,程序一开始就会执行print("AfterA_star"),而这时候后面的函数(包括helper,first_local_function,A_star)都还没有定义。所以,如果在print语句中直接或间接地引用了这些函数,就会出错。因此,除非用户明白移动代码对执行顺序的影响,否则我们不建议这样做。由于问题描述不充分,我们只能给出上述解释和手工调整步骤。如果用户有具体的代码,我们可以给出更具体的指导。但目前,我们只能提供一般方法。</think> 要在代码中将 `A_star` 函数定义后的所有语句移动到第一局部函数定义之前,需要遵循以下步骤: ### 操作步骤 1. **定位关键函数**: - 找到 `A_star` 函数定义结束的位置(通常是 `def A_star(...):` 的下一行) - 确定第一局部函数定义的位置(例如 `def local_function1(...):`) 2. **识别移动范围**: - 选中从 `A_star` 函数结束后的 **第一个可执行语句** 开始 - 到 **第一局部函数定义开始前** 的所有内容 - 注意:只移动 **非函数定义的语句**(赋值、循环、条件判断等) 3. **代码结构调整(示例)**: ```python # 原始结构 def first_local_function(): # [第一局部函数定义] ... def A_star(): # 目标函数 ... # 函数体 # ▼ 需要移动的语句(从这行开始)▼ x = 5 print("Initializing...") results = [] # ▲ 移动结束位置(到下一个函数定义前)▲ def helper_function(): # 其他局部函数 ... # 调整后结构 def first_local_function(): # [第一局部函数定义] ... # ▼ 被移动的语句现在出现在这里 ▼ x = 5 print("Initializing...") results = [] # ▲ 移动结束位置 ▲ def A_star(): # 目标函数位置不变 ... # 函数体 def helper_function(): # 其他局部函数 ... ``` ### 注意事项 1. **作用域影响**: - 移动后的语句将优先执行(在函数定义前运行) - 需确保移动的语句 **不依赖后续函数** 的变量或功能 - 避免在移动的语句中调用未定义的函数 2. **函数依赖处理**: - 若有被移动语句依赖的局部函数,需将其也提前定义 ```python # 调整依赖关系 def required_helper(): # 先定义依赖函数 ... # 被移动的语句 data = required_helper() # 现在可安全调用 ``` 3. **代码测试**: - 移动后务必测试: ```python if __name__ == "__main__": # 添加临时测试语句 print("All functions defined:", "A_star" in globals(), "helper_function" in globals()) ``` ### 示例场景 假设原始代码: ```python def initialize_system(): ... def A_star(start, goal): path = calculate_path(start, goal) # 依赖局部函数 return path # ▼ 要移动的语句 ▼ config = load_config("default.json") print("Using config:", config) # ▲ 移动结束 ▲ def calculate_path(a, b): # 第一局部函数 ... # 路径计算逻辑 ``` 调整后: ```python def initialize_system(): ... # 先定义依赖的局部函数 def calculate_path(a, b): # 被提前的局部函数 ... # 移动后的语句 config = load_config("default.json") print("Using config:", config) def A_star(start, goal): path = calculate_path(start, goal) # 安全调用 return path ``` ### 引用说明 在函数重定位时需保证: 1. 所有函数定义保持完整语法结构[^1] 2. 参数列表和内部变量作用域不受移动影响[^2] 3. 维护代码的封装性和执行逻辑完整性[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

talk_8

真诚赞赏,手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值