Nativescript 在 ListView 中向上滚动时显示元素 - 视差效果

Posted

技术标签:

【中文标题】Nativescript 在 ListView 中向上滚动时显示元素 - 视差效果【英文标题】:Nativescript Show element while scrolling up in ListView - parallax effect 【发布时间】:2019-01-12 12:03:22 【问题描述】:

我想获得有关如何实现在许多应用程序(如 Whatsapp 或 Facebook)中看到的功能的建议,在这些应用程序中,您有一个列表和一个不总是可见的标题,但当用户开始时会逐渐显示从列表中的任何位置向上滚动。

在 whatsapp 和 facebook 中,向上滚动手势会导致搜索栏慢慢出现在屏幕顶部,而列表本身不会滚动,直到搜索栏完全出现(至少这是 android 实现)。

我需要关于如何使用带有 Telerik RadListView (android + ios) 的 Nativescript angular 来实现这一点的建议。据我所知,telerik 通常不建议将 ListView 放在 ScrollView 中。

谢谢!

编辑:我了解到它被称为视差效果,并在原生 android 中找到了它的示例,但是,在带有 ListView 的 nativescript 中没有找到它(确实找到了一个带有 ScrollView 和常规 StackLayout 的示例,而不是ListView 里面)。

【问题讨论】:

【参考方案1】:

您可以在 NativeScript 市场官方网站的“示例”部分查看可用的“实现视差滚动效果”示例,该示例展示了如何实现该效果。只需转到Market.nativescript.org 并搜索“视差”。还有一个 plugin 提供了这样的功能,但我不确定它的质量。

【讨论】:

您好,感谢您的回复。我知道您所指的示例,这是我想到的那个:“确实找到了一个带有 ScrollView 和常规 StackLayout 的示例,而不是里面的 ListView”。它以非常简单的方式实现视差,然而,滚动部分是一个简单的 StackLayout,而不是 ListView。并且由于所有内容都包含在 ScrollView 中,因此无法以相同的方式实现,因为没有将 Listview 放入 ScrollView 的约束。 嗯,知道了。好吧,我还没有看到任何关于列表组件内视差效果的示例或讨论。您描述“始终不可见”的方式可能是在谈论“动态操作栏”而不是视差效果? 您好,我不确定确切的术语是什么,当您说“动态操作栏”时,您的意思是什么?我用谷歌搜索了它,但没有找到一个可以证明我要做什么的例子。我能给出的最好的例子是 SearchBar 在 android 上的 Whatsapp 和 Facebook 应用程序中隐藏和显示的方式,同时上下滚动列表。有些应用程序在发生这种情况时也有很好的动画效果,非常类似于视差示例,即在滚动底部布局时导致标题出现\缩小。 如果你在谈论这样的事情:androcode.es/wp-content/uploads/2015/10/simple_coordinator.gif,在来自“CoordinatorLayout”的 Android 上,我不确定 iOS 是否有类似的内置功能。在 NativeScript 中,CoordinatorLayout 不会被框架公开,但有人可以通过插件实现和公开它。 是的,非常相似,感谢您为我提供了正确的术语。我发现这个功能请求github.com/NativeScript/NativeScript/issues/4908 也谈到了它。【参考方案2】:

这是一个使用 Angular 实现的可滚动视差效果 RadListView 的示例(不需要 ScrollView)。它还提供了将列表标题粘贴在顶部的示例。

请告诉我它是否适合你。

组件模板:

<GridLayout class="page">
<RadListView (scrolled)="onScroll($event)" [items]="dataItems" itemReorder="true"
    (itemReordered)="onItemReordered($event)">
  <ListViewGridLayout tkListViewLayout scrollDirection="Vertical" spanCount="1" ios:itemHeight="150"
      dynamicItemSize="false"></ListViewGridLayout>

  <ng-template tkListItemTemplate let-item="item">
    <StackLayout orientation="vertical">
      <!-- list item content goes here -->
    </StackLayout>
  </ng-template>

  <ng-template tkListViewHeader>
    <StackLayout>
      <GridLayout #fixedHeaderContainer class="fixed-header-container">
        <label text="Fixed Content" verticalAlignment="center"></label>
      </GridLayout>

      <StackLayout class="list-header-container">
        <StackLayout #listHeaderContainer>
          <label text="List Title"></label>
        </StackLayout>
      </StackLayout>
    </StackLayout>
  </ng-template>
</RadListView>

<GridLayout verticalAlignment="top" [height]="dockContainerHeight" [opacity]="dockContainerOpacity">
  <FlexboxLayout justifyContent="flex-start" alignItems="center" class="docked-label-wrapper">
    <button class="fas" text="&#xf053;"></button>

    <StackLayout flexGrow="1"  [opacity]="dockContentOpacity" orientation="horizontal">
      <label text="List Title"></label>
    </StackLayout>
  </FlexboxLayout>
</GridLayout>
组件scss:
.fixed-header-container 
  height: 200;
  padding: 0 16;
  background-color: green;

  label 
    font-size: 30;
    font-weight: 700;
    color: $white;
  


.list-header-container 
  margin-top: -12;
  border-radius: 12 12 0 0;
  background-color: #ffffff;

  label 
    margin: 16 0;
    font-size: 22;
    color: black;
    vertical-align: center;
  

  .smaller-label 
    font-size: 12;
    color: #909090;
  


RadListView 
  height: 100%;
  background-color: #ffffff;


.docked-label-wrapper 
  margin: 0 0 10;
  background-color: #ffffff;

  .fas 
    margin: 0;
    font-size: 18;
  

  label 
    font-size: 18;
    color: black;
    vertical-align: center;
  

组件 ts:

  import  Component, ElementRef, OnInit, ViewChild  from '@angular/core';
  import  ListViewEventData, ListViewScrollEventData  from 'nativescript-ui-listview';
  import  DataItem, DataItemService  from './data-items.service';

  export const DOCK_HEADER_HEIGHT = 58;

  @Component(
    moduleId: module.id,
    selector: 'app-comp-name',
    templateUrl: './comp-name.component.html',
    styleUrls: ['./comp-name.component.scss']
  )
  export class CompNameComponent implements OnInit 
    dataItems: DataItem[];
    dockContainerHeight = DOCK_HEADER_HEIGHT;
    dockContainerOpacity = 0;
    dockContentOpacity = 0;

    @ViewChild('fixedHeaderContainer',  static: false )
    fixedHeaderContainerRef: ElementRef;

    @ViewChild('listHeaderContainer')
    listHeaderContainerRef: ElementRef;

    constructor(private _dataItemService: DataItemService) 

    ngOnInit(): void 
        this.dataItems = this._dataItemService.getDataItems();
    

    onItemReordered(args: ListViewEventData) 
        console.log('Item reordered. Old index: ' + args.index + ' ' + 'new index: ' + args.data.targetIndex);
    

    onScroll(args: ListViewScrollEventData) 
        if (!this.fixedHeaderContainerRef) 
        return;
        

        const offset = args.scrollOffset < 0 ? 0 : args.scrollOffset;
        const fixedHeaderHeight = this.fixedHeaderContainerRef.nativeElement.getActualSize().height;

        this.applyFixedHeaderTransition(offset);
        this.applyTitleTransition(offset, fixedHeaderHeight);
        this.applyDockHeaderTransition(offset, fixedHeaderHeight);
    

    private applyFixedHeaderTransition(scrollOffset: number) 
        this.fixedHeaderContainerRef.nativeElement.translateY = scrollOffset;
    

    private applyTitleTransition(scrollOffset: number, fixedHeaderHeight: number) 
        const maxHeightChange = fixedHeaderHeight - DOCK_HEADER_HEIGHT;
        const titleElement = this.listHeaderContainerRef.nativeElement;

        if (maxHeightChange < scrollOffset) 
        titleElement.translateX = -(scrollOffset - maxHeightChange) / 1.2;
        titleElement.translateY = -(scrollOffset - maxHeightChange) * 2;
        titleElement.scaleX = 1 - (scrollOffset - maxHeightChange) / fixedHeaderHeight;
        titleElement.scaleY = 1 - (scrollOffset - maxHeightChange) / fixedHeaderHeight;
         else 
        titleElement.translateX = 0;
        titleElement.translateY = 0;
        titleElement.scaleX = 1;
        titleElement.scaleY = 1;
        
    

    private applyDockHeaderTransition(scrollOffset: number, fixedHeaderHeight: number) 
        const maxHeightChange = fixedHeaderHeight - DOCK_HEADER_HEIGHT;
        const containerOpacity = 1 - scrollOffset / maxHeightChange;

        this.dockContainerOpacity = containerOpacity <= 0 ? 1 : 0;
        this.dockContentOpacity = (scrollOffset - (fixedHeaderHeight - DOCK_HEADER_HEIGHT)) / DOCK_HEADER_HEIGHT - 0.2;
    
  

【讨论】:

以上是关于Nativescript 在 ListView 中向上滚动时显示元素 - 视差效果的主要内容,如果未能解决你的问题,请参考以下文章

Nativescript 在 ListView 中向上滚动时显示元素 - 视差效果

水平 StackLayout 中的 ListView - Nativescript Vue

Nativescript-Vue:如何在 ListView 中正确使用 v-for

ListView 不在 ScrollView 和 StackLayout 内呈现,在 ios 中具有水平方向 - nativescript-vue

Nativescript Vue:从ListView中的itemTap获取数组中的项目

使用 ListView 和 nativescript-vue 进行无限滚动