/*
* Created by LuaView.
* Copyright (c) 2017, Alibaba Group. All rights reserved.
*
* This source code is licensed under the MIT.
* For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
*/
package com.taobao.luaview.userdata.list;
import android.graphics.Point;
import android.view.ViewGroup;
import android.widget.AbsListView;
import com.taobao.luaview.cache.SparseCache;
import com.taobao.luaview.global.LuaView;
import com.taobao.luaview.provider.ImageProvider;
import com.taobao.luaview.userdata.ui.UDViewGroup;
import com.taobao.luaview.util.AndroidUtil;
import com.taobao.luaview.util.DimenUtil;
import com.taobao.luaview.util.LuaUtil;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* UDBaseListView or RecyclerView
*
* @author song
* @date 15/10/23
*/
public abstract class UDBaseListOrRecyclerView<T extends ViewGroup> extends UDViewGroup<T> {
//初始化数据
private LuaValue mSectionDelegate;
protected LuaValue mCellDelegate;
//view type map
private AtomicBoolean isSectionLengthInit = new AtomicBoolean(false);
private Point[] mSectionLength;//长度数组,每个point的x为开始位置(包含),y为结束位置(不包含),(y-x)为该组长度
protected HashMap<String, Integer> mViewTypeMap = new HashMap<String, Integer>();//view类型集合,从0开始,不能放到init中初始化
protected HashMap<Integer, String> mViewTypeNameMap = new HashMap<Integer, String>();//View类型名称集合,不能放到init中初始化
//id
protected SparseCache<String> mIdCache;
//延迟加载
protected boolean mLazyLoad = true;
public UDBaseListOrRecyclerView(T view, Globals globals, LuaValue metaTable, Varargs initParams) {
super(view, globals, metaTable, initParams);
init();
}
/**
* 初始化数据
*/
public void init() {
if (this.initParams != null) {
this.mIdCache = new SparseCache<String>();
this.mSectionDelegate = LuaUtil.getValue(initParams, "Section");
this.mCellDelegate = LuaUtil.getValue(initParams, "Cell");
this.mCallback = LuaUtil.getValue(initParams, "Callback");
initSectionLength();
}
}
/**
* 初始化section的长度
*/
private void initSectionLength() {
isSectionLengthInit.set(false);
final int numOfSections = getSectionCount();
if (numOfSections > 0) {
mSectionLength = new Point[numOfSections];
int left = 0, right = 0;
for (int i = 0; i < numOfSections; i++) {
left = right;
right = right + getRowCount(i);
mSectionLength[i] = new Point(left, right);
}
}
isSectionLengthInit.set(true);
}
//-----------------------------------------section----------------------------------------------
/**
* 获取新的总数跟老的总数差别
*
* @return
*/
public int getDiffTotalCount() {
int oldCount = (isSectionLengthInit.get() && mSectionLength != null) ? mSectionLength[mSectionLength.length - 1].y : 0;
int newCount = getRawTotalCount();
return newCount - oldCount;
}
/**
* 获取总的个数
*
* @return
*/
public int getTotalCount() {
if (isSectionLengthInit.get()) {
return mSectionLength != null ? mSectionLength[mSectionLength.length - 1].y : 0;
} else {
final int totalSections = getSectionCount();
int totalCount = 0;
for (int i = 0; i < totalSections; i++) {
totalCount += getRowCount(i);
}
return totalCount;
}
}
/**
* 获取原始总个数
*
* @return
*/
protected int getRawTotalCount() {
final int totalSections = getRawSectionCount();
int totalCount = 0;
for (int i = 0; i < totalSections; i++) {
totalCount += getRawRowCount(i);
}
return totalCount;
}
/**
* 返回新count 跟 老count的差距
*
* @return
*/
protected int getDiffSectionCount() {
int oldCount = (isSectionLengthInit.get() && mSectionLength != null) ? mSectionLength.length : 0;
int newCount = getRawSectionCount();
return newCount - oldCount;
}
/**
* 分区个数,android的totalCount=分区个数*每个分区的数目
*
* @return
*/
protected int getSectionCount() {
if (isSectionLengthInit.get()) {
return mSectionLength != null ? mSectionLength.length : 0;
} else {
return getRawSectionCount();
}
}
/**
* 获取原始的SectionCount
*
* @return
*/
protected int getRawSectionCount() {
if (this.mSectionDelegate == null) {
return 0;
}
return LuaUtil.getOrCallFunction(this.mSectionDelegate.get("SectionCount")).optint(1);
}
/**
* 获取diff of new RowCount and old RowCount of Section
*
* @param section
* @return
*/
protected int diffRowCount(int section) {
int oldCount = (isSectionLengthInit.get() && mSectionLength != null) ? (this.mSectionLength[section].y - this.mSectionLength[section].x) : 0;
int newCount = getRawRowCount(section);
return newCount - oldCount;
}
/**
* 每个分区的行数,section从0开始
*
* @param section
* @return
*/
protected int getRowCount(int section) {
if (isSectionLengthInit.get()) {
return mSectionLength != null ? (this.mSectionLength[section].y - this.mSectionLength[section].x) : 0;
} else {
return getRawRowCount(section);
}
}
/**
* 读取RowCount,获取原始count
*
* @param section
* @return
*/
protected int getRawRowCount(int section) {
return LuaUtil.callFunction(this.mSectionDelegate.get("RowCount"), LuaUtil.toLuaInt(section)).optint(0);
}
//------------------------------------------cell------------------------------------------------
/**
* get position by section and rowInSection
*
* @param section
* @param rowInSection
* @return
*/
protected int getPositionBySectionAndRow(int section, int rowInSection) {
if (mSectionLength != null) {
if (section >= 0 && section < mSectionLength.length) {
return mSectionLength[section].x + rowInSection;
} else {
return 0;
}
}
return rowInSection;
}
/**
* 根据position来判断该位置属于哪个position
*
* @param position
* @return
*/
protected int getSectionByPosition(int position) {
if (mSectionLength != null) {
for (int i = 0; i < mSectionLength.length; i++) {
if (position >= mSectionLength[i].x && position < mSectionLength[i].y) {
return i;
}
}
}
return 0;
}
/**
* 根据position来判断该位置位于section的第几个位置
*
* @param position
* @return
*/
protected int getRowInSectionByPosition(int position) {
if (mSectionLength != null) {
final int section = getSectionByPosition(position);
return position - mSectionLength[section].x;
} else {
return 0;
}
}
/**
* 根据position获取某个cell的类型
*
* @param position
* @return
*/
public String getId(int position) {
return getId(position, getSectionByPosition(position), getRowInSectionByPosition(position));
}
/**
* 根据section, row获取cell的Id
*
* @param position
* @param section
* @param row
* @return
*/
protected String getId(int position, int section, int row) {
final String cacheId = mIdCache != null ? mIdCache.get(position) : null;
if (cacheId != null) {
return cacheId;
} else {
final String id = LuaUtil.callFunction(mCellDelegate.get("Id"), LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row)).optjstring("");
if (mIdCache != null) {
mIdCache.put(position, id);
}
return id;
}
}
/**
* 根据id获取某个cell
*
* @param id
* @return
*/
public LuaValue getCell(String id) {
return mCellDelegate.get(id);
}
/**
* 是否有size的定义
*
* @param position
* @return
*/
public boolean hasCellSize(int position) {
return hasCellFunction(position, "Size");
}
/**
* return width, height
*
* @param cell
* @param position
* @return
*/
public int[] callCellSize(LuaValue cell, int position, int... defaultSize) {
final Varargs size = invokeCellSize(cell, position);
int defaultWidth = (defaultSize != null && defaultSize.length > 1) ? defaultSize[0] : AndroidUtil.getScreenWidth(getContext());
int width = 0, height = 0;
if (size != null) {
if (size.narg() > 1) {//width & height
width = DimenUtil.dpiToPx(size.arg(1), defaultWidth);
height = DimenUtil.dpiToPx(size.arg(2));
} else {
width = defaultWidth;
height = DimenUtil.dpiToPx(size.arg(1));
}
}
return new int[]{width, height};
}
/**
* 调用 Size 方法 (返回多个值)
*
* @param cell
* @param position
* @return
*/
public Varargs invokeCellSize(LuaValue cell, int position) {
// return invokeCellFunction("Size", cell, position);
return invokeCellFunction("Size", position);//不带cell
}
/**
* 调用 Init 方法
*
* @param cell
* @param position
* @return
*/
public LuaValue callCellInit(LuaValue cell, int position) {
return callCellFunction("Init", cell, position);//Lua从1开始
}
/**
* 调用 Layout 方法
*
* @param cell
* @param position
* @return
*/
public LuaValue callCellLayout(LuaValue cell, int position) {
return callCellFunction("Layout", cell, position);
}
/**
* 调用 Callback 方法
*
* @param cell
* @param position
* @return
*/
public LuaValue onCellClicked(LuaValue cell, int position) {
final int section = getSectionByPosition(position);
final int row = getRowInSectionByPosition(position);
final String id = getId(position, section, row);
final LuaValue cellData = getCell(id);
if (cellData != null) {
final LuaValue callback = cellData.get("Callback");
if (callback.isfunction()) {
return LuaUtil.callFunction(callback, cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
} else if (callback.istable()) {
return LuaUtil.callFunction(LuaUtil.getFunction(callback, "Click", "click"), cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
}
}
return NIL;
}
/**
* 调用 Callback 方法
*
* @param cell
* @param position
* @return
*/
public boolean onCellLongClicked(LuaValue cell, int position) {
final int section = getSectionByPosition(position);
final int row = getRowInSectionByPosition(position);
final String id = getId(position, section, row);
final LuaValue cellData = getCell(id);
if (cellData != null) {
final LuaValue callback = cellData.get("Callback");
if (callback != null && callback.istable()) {
return LuaUtil.callFunction(LuaUtil.getFunction(callback, "LongClick", "longClick"), cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row)).optboolean(false);
}
}
return false;
}
/**
* 调用cell的某个方法
*
* @param method
* @param cell
* @param position
* @return
*/
private LuaValue callCellFunction(String method, LuaValue cell, int position) {
final int section = getSectionByPosition(position);
final int row = getRowInSectionByPosition(position);
return callCellFunction(getId(position, section, row), method, cell, section, row);
}
/**
* 调用cell的某个方法,返回多个值
*
* @param method
* @param cell
* @param position
* @return
*/
private Varargs invokeCellFunction(String method, LuaValue cell, int position) {
final int section = getSectionByPosition(position);
final int row = getRowInSectionByPosition(position);
return invokeCellFunction(getId(position, section, row), method, cell, section, row);
}
/**
* 调用cell的某个方法,返回多个值
*
* @param method
* @param position
* @return
*/
private Varargs invokeCellFunction(String method, int position) {
final int section = getSectionByPosition(position);
final int row = getRowInSectionByPosition(position);
return invokeCellFunction(getId(position, section, row), method, section, row);
}
/**
* 调用cell的某个方法
*
* @param id
* @param method
* @param cell
* @param section
* @param row
* @return
*/
private LuaValue callCellFunction(String id, String method, LuaValue cell, int section, int row) {
final LuaValue methodData = getCell(id);
if (!methodData.isnil()) {
return LuaUtil.callFunction(methodData.get(method), cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
}
return NIL;
}
/**
* 调用cell的某个方法 (返回多个值)
*
* @param id
* @param method
* @param cell
* @param section
* @param row
* @return
*/
private Varargs invokeCellFunction(String id, String method, LuaValue cell, int section, int row) {
final LuaValue methodData = getCell(id);
if (!methodData.isnil()) {
return LuaUtil.invokeFunction(methodData.get(method), cell, LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
}
return NIL;
}
/**
* 调用cell的某个方法 (返回多个值)
*
* @param id
* @param method
* @param section
* @param row
* @return
*/
private Varargs invokeCellFunction(String id, String method, int section, int row) {
final LuaValue methodData = getCell(id);
if (!methodData.isnil()) {
return LuaUtil.invokeFunction(methodData.get(method), LuaUtil.toLuaInt(section), LuaUtil.toLuaInt(row));
}
return NIL;
}
/**
* 是否有某个函数
*
* @param method
* @param position
* @return
*/
private boolean hasCellFunction(int position, String method) {
final int section = getSectionByPosition(position);
final int row = getRowInSectionByPosition(position);
final String id = getId(position, section, row);
return hasCellFunction(id, method);
}
/**
* 是否有某个函数
*
* @param cellId
* @param method
* @return
*/
public boolean hasCellFunction(String cellId, String method) {
final LuaValue methodData = getCell(cellId);
return !methodData.isnil() && methodData.get(method) != null && methodData.get(method).isfunction();
}
/**
* 获取key map
*
* @return
*/
public HashMap<String, Integer> getCellKeyMap() {
HashMap<String, Integer> result = new HashMap<String, Integer>();
if (mCellDelegate != null) {
LuaValue[] keys = this.mCellDelegate.checktable().keys();
if (keys != null) {
for (int i = 0; i < keys.length; i++) {
result.put(keys[i].toString(), i);
}
}
}
return result;
}
/**
* 根据位置获取 item 的type id
*
* @param position
* @return
*/
public int getItemViewType(int position) {
final String viewTypeName = getId(position);//得到坑位类型名称
if (this.mViewTypeMap != null) {
if (!this.mViewTypeMap.containsKey(viewTypeName)) {
final int index = this.mViewTypeMap.size();
this.mViewTypeMap.put(viewTypeName, index);
this.mViewTypeNameMap.put(index, viewTypeName);
return index;
}
return this.mViewTypeMap.get(viewTypeName);
}
return 0;
}
/**
* 获取ViewType的name
*
* @param viewType
* @return
*/
public String getItemViewTypeName(int viewType) {
if (this.mViewTypeNameMap != null) {
return this.mViewTypeNameMap.get(viewType);
}
return null;
}
/**
* 这里不是真实的viewType的数字,只是获取Cell中的属性数目(该属性数目一定比cell种数多)
* TODO 这里通过读取ID的方式获取所有的count
*
* @return
*/
public int getViewTypeCount() {
return getCellKeyMap().size();
}
public UDBaseListOrRecyclerView setLazyLoad(boolean mLazyLoad) {
this.mLazyLoad = mLazyLoad;
return this;
}
//-----------------------------------------lazy load--------------------------------------------
/**
* 更新所有子view的ScrollState,用于延迟加载
*
* @param view
* @param scrollState
*/
protected void updateAllChildScrollState(ViewGroup view, int scrollState) {
if (this.mLazyLoad && view != null) {
if (scrollState >= AbsListView.OnScrollListener.SCROLL_STATE_FLING) {//手滑动的时候
final ImageProvider provider = LuaView.getImageProvider();
if (provider != null) {
provider.pauseRequests(view, getContext());
}
} else {
final ImageProvider provider = LuaView.getImageProvider();
if (provider != null) {
provider.resumeRequests(view, getContext());
}
}
}
}
//------------------------------------------Scroll----------------------------------------------
/**
* 初始化滚动回调
*/
public abstract void initOnScrollCallback(final T view);
//------------------------------------------功能------------------------------------------------
/**
* 重新加载
*
* @return
*/
public abstract UDBaseListOrRecyclerView reload(Integer section, Integer row);
/**
* listview滚动到顶部
*
* @param animate 是否动画
* @return
*/
public abstract UDBaseListOrRecyclerView scrollToTop(final int offset, final boolean animate);
/**
* listview滚动到某个位置
*
* @param section
* @param rowInSection
* @param offset
* @return
*/
public abstract UDBaseListOrRecyclerView scrollToItem(final int section, final int rowInSection, final int offset, final boolean animate);
/**
* 设置item最小间隔
*
* @param spacing
* @return
*/
public abstract UDBaseListOrRecyclerView setMiniSpacing(final int spacing);
/**
* 获取item最小间隔
*
* @return
*/
public abstract int getMiniSpacing();
}