[Delphi] FMXUI - ListView用法簡介


在 FMXUI 中,有 TListExView 和 TListViewEx 兩個ListView。其中第一個是對Delphi原有TListView的功能擴展版,用法和原有的基本一樣。TListViewEx 則是 FMXUI 原創的一個 ListView , 今天我們要介紹的就是它了。

一、 IListAdapter 數據適配器

 

TListViewEx 的設計思想與Java原生安卓開發類似,使用了數據與顯示分離的適配器模式。組件本身不存放數據,只負責顯示控制。用戶可以使用自帶的幾個簡單的數據適配器或者實現IListAdapter接口,打造自己的數據適配器。通過自帶義數據適配器,我們可以實現任意樣式的列表。所以,這里的 IListAdapter 接口的重要性不言而預。

 

我們來看看 IListAdapter 的定義:

 

  /// <summary>
  /// 列表適配器接口
  /// </summary>
  IListAdapter = interface
    ['{5CC5F4AB-2D8C-4A84-98A7-51566E38EA47}']
    function GetCount: Integer;
    function GetItemID(const Index: Integer): Int64;
    function GetItem(const Index: Integer): Pointer;
    function IndexOf(const AItem: Pointer): Integer;
    function GetView(const Index: Integer; ConvertView: TViewBase; Parent: TViewGroup): TViewBase;
    function GetItemViewType(const Index: Integer): Integer;
    function IsEmpty: Boolean;
    function IsEnabled(const Index: Integer): Boolean;
    function ItemDefaultHeight: Single;
    procedure Clear;
    procedure Repaint;
    procedure NotifyDataChanged;
    property Count: Integer read GetCount;
    property Items[const Index: Integer]: Pointer read GetItem; default;
  end;

 

  • GetCount: 返回數據的大小(總行數)
  • GetItemID: 指定索引項數據的ID(可以直接使用索引號)
  • GetItem: 獲取指定索引的數據
  • IndexOf: 查找數據,返回索引號
  • GetView: 根據索引號,返回對應的可視對象(這個超級重要!!)
  • GetItemViewtype: 返回指定索引號的視圖類型(這個也是重點)
  • IsEmpty: 判斷列表是否為空(Count = 0)
  • IsEnabled: 判斷某行數據是否有效
  • ItemDefaultHeight: 默認行高度(很重要,返回所有視圖類型中的最大默認行高)
  • Clear: 清空數據
  • Repaint: 重繪
  • NotifyDataChanged: 通知列表框組件數據已經更新,需要重新繪制
  • Count: 數據的總數

 

在接口中, 最常用的 GetView , GetItemViewType, ItemDefaultHeight , GetCount 這四個。一般情況我們只需要繼承 TListAdapterBase 或者 TListAdapter , 然后重載這四個函數就可以了。

 

二、 使用 ListView

我們實現如下效果。

第一步: 創建自定義列表項視圖。

添加一個Frame,命名為 CustomListView_ListItem 。然后設計成這樣:

第二步: 創建數據適配器

type
  TDataItem = record
    Name: string;
    Phone: string;
    Color: TAlphaColor;
  end;

  TCustomListDataAdapter = class(TListAdapterBase)
  private
    [Weak] FList: TList<TDataItem>;
  protected
    function GetCount: Integer; override;
    function ItemDefaultHeight: Single; override;
    function GetItem(const Index: Integer): Pointer; override;
    function IndexOf(const AItem: Pointer): Integer; override;
    function GetView(const Index: Integer; ConvertView: TViewBase;
      Parent: TViewGroup): TViewBase; override;
  public
    constructor Create(const AList: TList<TDataItem>);
  end;


....


{ TCustomListDataAdapter }

constructor TCustomListDataAdapter.Create(const AList: TList<TDataItem>);
begin
  FList := AList;
end;

function TCustomListDataAdapter.GetCount: Integer;
begin
  if Assigned(FList) then
    Result := FList.Count
  else
    Result := 0;
end;

function TCustomListDataAdapter.GetItem(const Index: Integer): Pointer;
begin
  Result := nil;
end;

function TCustomListDataAdapter.GetView(const Index: Integer;
  ConvertView: TViewBase; Parent: TViewGroup): TViewBase;
var
  ViewItem: TCustomListView_ListItem;
  Item: TDataItem;
begin
  if (ConvertView = nil) or (not (ConvertView.ClassType = TCustomListView_ListItem)) then begin
    ViewItem := TCustomListView_ListItem.Create(Parent);
    ViewItem.Parent := Parent;
    ViewItem.Width := Parent.Width;
    ViewItem.CanFocus := False;
  end else
    ViewItem := TObject(ConvertView) as TCustomListView_ListItem;

  Item := FList.Items[Index];
  ViewItem.BeginUpdate;
  ViewItem.TextView1.Text := Item.Name;
  ViewItem.TextView2.Text := Item.Phone;
  ViewItem.View1.Background.ItemDefault.Color := Item.Color;
  ViewItem.EndUpdate;
  Result := TViewBase(ViewItem);
end;

function TCustomListDataAdapter.IndexOf(const AItem: Pointer): Integer;
begin
  Result := -1;
end;

function TCustomListDataAdapter.ItemDefaultHeight: Single;
begin
  Result := 72;
end;

第三步、應用數據適配器

在窗口上添加 TListViewEx,命名為 ListView。 在窗口初始化事件中, 初始化數據適配器。

procedure TCustomListview.DoCreate;
begin
  inherited;
  FList := TList<TDataItem>.Create();
  FAdapter := TCustomListDataAdapter.Create(FList);
end;

在窗口 Show 事件中,為 ListView 指定數據適配器。

procedure TCustomListview.DoShow;
begin
  inherited;
  ListView.Adapter := FAdapter;
  AddItems(20); // 添加20行測試數據 end;

在窗口釋放事件中,釋放資源

procedure TCustomListview.DoFree;
begin
  inherited;
  ListView.Adapter := nil;
  FAdapter := nil;
  FreeAndNil(FList);
end;

添加測試數據的代碼

procedure TCustomListview.AddItems(const Count: Integer);
var
  I: Integer;
  Item: TDataItem;
begin
  for I := 0 to Count - 1 do begin
    Item.Name := '用戶名稱' + IntToStr(I);
    if I mod 2 = 0 then
      Item.Color := TAlphaColorRec.Crimson
    else
      Item.Color := TAlphaColorRec.Yellow;
    Item.Phone := '131 0000 0000';
    FList.Add(Item);
  end;
  FAdapter.NotifyDataChanged;
end;

注意: 數據變更后,需要及時調用 NotifyDataChanged 來通知 ListView 更新顯示。

 

三、 下拉刷新和上拉加載更多

TListViewEx 也實現了下拉刷新和上拉加載更多的功能。在屬性面板中啟用相應的選項即可。

 

  • EnablePullRefresh: 是否啟用下拉刷新
  • EnablePullLoad: 是否啟用上拉加載更多
  • OnInitFooter: 加載自定義 Footer 事件, 如果不設置,將在需要時加載默認的 Footer
  • OnInitHeader: 加載自定義 Header 事件, 如果不設置,將在需要時加載默認的 Header
  • OnPullRefresh: 下拉刷新事件
  • OnPullLoad: 上拉加載更多事件

 

TListViewEx 允許自定義 Footer 和 Header, 只需要在上述相應的事件中,初始化為對應的視圖就可以了。自定義視圖的實現方式也是新建一個 Frame 就可以了, 參考 ListItem 和默認的實現。不同的時需要實現 IListViewHeader 接口。

 

示例:

procedure TCustomListview.ListViewPullLoad(Sender: TObject);
begin
  DelayExecute(1,
    procedure (Sender: TObject)
    begin
      AddItems(20);
      ListView.PullLoadComplete;
    end
  );
end;

procedure TCustomListview.ListViewPullRefresh(Sender: TObject);
begin
  Hint('正在加載數據');
  DelayExecute(2,
    procedure (Sender: TObject)
    begin
      FList.Clear;
      AddItems(20);
      ListView.PullRefreshComplete;
    end
  );
end;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM