/* Copyright (c) 2020 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using Tizen.NUI.BaseComponents;
using System.Collections.Generic;
using System.ComponentModel;
namespace Tizen.NUI.Components
{
///
/// [Draft] This class provides a View that can recycle items to improve performance.
///
/// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public class RecyclerView : ScrollableBase
{
protected RecycleAdapter mAdapter;
protected View mContainer;
protected RecycleLayoutManager mLayoutManager;
protected int mTotalItemCount = 15;
private List notifications = new List();
public RecyclerView() : base()
{
Initialize(new RecycleAdapter(), new RecycleLayoutManager());
}
///
/// Default constructor.
///
/// Recycle adapter of RecyclerView.
/// Recycle layoutManager of RecyclerView.
/// 8
/// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
[EditorBrowsable(EditorBrowsableState.Never)]
public RecyclerView(RecycleAdapter adapter, RecycleLayoutManager layoutManager)
{
Initialize(adapter, layoutManager);
}
private void Initialize(RecycleAdapter adapter, RecycleLayoutManager layoutManager)
{
Scrolling += OnScrolling;
mAdapter = adapter;
mAdapter.OnDataChanged += OnAdapterDataChanged;
mLayoutManager = layoutManager;
mLayoutManager.Container = ContentContainer;
mLayoutManager.ItemSize = mAdapter.CreateRecycleItem().Size;
mLayoutManager.DataCount = mAdapter.Data.Count;
InitializeItems();
}
private void OnItemSizeChanged(object source, PropertyNotification.NotifyEventArgs args)
{
mLayoutManager.Layout(ScrollingDirection == Direction.Horizontal ? ContentContainer.CurrentPosition.X : ContentContainer.CurrentPosition.Y);
}
public int TotalItemCount
{
get
{
return mTotalItemCount;
}
set
{
mTotalItemCount = value;
InitializeItems();
}
}
private void InitializeItems()
{
for(int i = Children.Count -1 ; i > -1 ; i--)
{
Children[i].Unparent();
notifications[i].Notified -= OnItemSizeChanged;
notifications.RemoveAt(i);
}
for (int i = 0; i < mTotalItemCount; i++)
{
RecycleItem item = mAdapter.CreateRecycleItem();
item.DataIndex = i;
item.Name = "[" + i + "] recycle";
if (i < mAdapter.Data.Count)
{
mAdapter.BindData(item);
}
Add(item);
PropertyNotification noti = item.AddPropertyNotification("size", PropertyCondition.Step(0.1f));
noti.Notified += OnItemSizeChanged;
notifications.Add(noti);
}
mLayoutManager.Layout(0.0f);
if (ScrollingDirection == Direction.Horizontal)
{
ContentContainer.SizeWidth = mLayoutManager.CalculateLayoutOrientationSize();
}
else
{
ContentContainer.SizeHeight = mLayoutManager.CalculateLayoutOrientationSize();
}
}
public new Direction ScrollingDirection
{
get
{
return base.ScrollingDirection;
}
set
{
base.ScrollingDirection = value;
if (ScrollingDirection == Direction.Horizontal)
{
ContentContainer.SizeWidth = mLayoutManager.CalculateLayoutOrientationSize();
}
else
{
ContentContainer.SizeHeight = mLayoutManager.CalculateLayoutOrientationSize();
}
}
}
///
/// Recycler adpater.
///
/// 8
/// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
[EditorBrowsable(EditorBrowsableState.Never)]
public RecycleAdapter Adapter
{
get
{
return mAdapter;
}
set
{
if(mAdapter != null)
{
mAdapter.OnDataChanged -= OnAdapterDataChanged;
}
mAdapter = value;
mAdapter.OnDataChanged += OnAdapterDataChanged;
mLayoutManager.ItemSize = mAdapter.CreateRecycleItem().Size;
mLayoutManager.DataCount = mAdapter.Data.Count;
InitializeItems();
}
}
///
/// Recycler layoutManager.
///
/// 8
/// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
[EditorBrowsable(EditorBrowsableState.Never)]
public RecycleLayoutManager LayoutManager
{
get
{
return mLayoutManager;
}
set
{
mLayoutManager = value;
mLayoutManager.Container = ContentContainer;
mLayoutManager.ItemSize = mAdapter.CreateRecycleItem().Size;
mLayoutManager.DataCount = mAdapter.Data.Count;
InitializeItems();
}
}
private void OnScrolling(object source, ScrollEventArgs args)
{
mLayoutManager.Layout(ScrollingDirection == Direction.Horizontal ? args.Position.X : args.Position.Y);
List recycledItemList = mLayoutManager.Recycle(ScrollingDirection == Direction.Horizontal ? args.Position.X : args.Position.Y);
BindData(recycledItemList);
}
private void OnAdapterDataChanged(object source, EventArgs args)
{
List changedData = new List();
foreach (RecycleItem item in Children)
{
changedData.Add(item);
}
BindData(changedData);
}
private void BindData(List changedData)
{
foreach (RecycleItem item in changedData)
{
if (item.DataIndex > -1 && item.DataIndex < mAdapter.Data.Count)
{
item.Show();
item.Name = "["+item.DataIndex+"]";
mAdapter.BindData(item);
}
else
{
item.Hide();
}
}
}
///
/// Adjust scrolling position by own scrolling rules.
/// Override this function when developer wants to change destination of flicking.(e.g. always snap to center of item)
///
/// Scroll position which is calculated by ScrollableBase
/// Adjusted scroll destination
/// 8
/// This may be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API
[EditorBrowsable(EditorBrowsableState.Never)]
protected override float AdjustTargetPositionOfScrollAnimation(float position)
{
// Destination is depending on implementation of layout manager.
// Get destination from layout manager.
return mLayoutManager.CalculateCandidateScrollPosition(position);
}
}
}