remove expandablelistview,use recyclerview PLS

This commit is contained in:
houzh 2024-01-25 00:27:02 +08:00
parent 98e2ac97a1
commit 2d42312380
18 changed files with 132 additions and 2346 deletions

View File

@ -2,8 +2,23 @@
namespace cdroid{
int Parcel::readInt(){
return 0;
return 0;
}
bool Parcel::readBoolean(){
return readInt()!=0;
}
std::string Parcel::readString(){
return std::string();
}
void Parcel::writeInt(int val){
}
void Parcel::writeBoolean(bool){
}
void Parcel::writeString(const std::string&){
}
}

View File

@ -60,12 +60,14 @@ public:
void recycle();
uint8_t readByte();
int readInt();
bool readBoolean();
float readFloat();
double readDouble();
std::string readString();
void writeByte(uint8_t val);
void writeInt(int32_t val);
void writeBoolean(bool);
void writeFloat(float val);
void writeDouble(double val);
void writeString(const std::string& val);

View File

@ -1,5 +1,6 @@
#ifndef __PARCELABLE_H__
#define __PARCELABLE_H__
class Parcel;
namespace cdroid{
class Parcelable {
public:

33
src/gui/view/abssavedstate.cc Executable file
View File

@ -0,0 +1,33 @@
#include <view/abssavedstate.h>
namespace cdroid{
AbsSavedState AbsSavedState::EMPTY_STATE;
AbsSavedState::AbsSavedState() {
mSuperState = nullptr;
}
AbsSavedState::AbsSavedState(Parcelable* superState) {
LOGE_IF(superState == nullptr,"superState must not be null");
mSuperState = superState != &EMPTY_STATE ? superState : nullptr;
}
AbsSavedState::AbsSavedState(Parcel& source) {
//this(source, null);
}
/*AbsSavedState(Parcel& source, ClassLoader loader) {
Parcelable superState = source.readParcelable(loader);
mSuperState = superState != null ? superState : EMPTY_STATE;
}*/
Parcelable* AbsSavedState::getSuperState() {
return mSuperState;
}
int AbsSavedState::describeContents() {
return 0;
}
void AbsSavedState::writeToParcel(Parcel& dest, int flags) {
//dest.writeParcelable(mSuperState, flags);
}
}

21
src/gui/view/abssavedstate.h Executable file
View File

@ -0,0 +1,21 @@
#ifndef __ABS_SAVED_STATE_H__
#define __ABS_SAVED_STATE_H__
#include <core/parcelable.h>
#include <core/parcel.h>
namespace cdroid{
class AbsSavedState:public Parcelable {
public:
static AbsSavedState EMPTY_STATE;
private:
Parcelable* mSuperState;
AbsSavedState();
protected:
AbsSavedState(Parcelable* superState);
AbsSavedState(Parcel& source);
public:
Parcelable* getSuperState();
int describeContents();
void writeToParcel(Parcel& dest, int flags);
};
}/*endof namespace*/
#endif

View File

@ -1448,7 +1448,7 @@ void View::saveHierarchyState(SparseArray<Parcelable*>& container){
void View::dispatchSaveInstanceState(SparseArray<Parcelable*>& container){
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
Parcelable* state = onSaveInstanceState();
Parcelable* state = onSaveInstanceState();
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
LOGE("Derived class did not call super.onSaveInstanceState()");
}
@ -1461,29 +1461,30 @@ void View::dispatchSaveInstanceState(SparseArray<Parcelable*>& container){
Parcelable* View::onSaveInstanceState(){
#if 0
#define LAST_APP_AUTOFILL_ID 100000
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (mStartActivityRequestWho != null || isAutofilled()
if (mStartActivityRequestWho.size() || isAutofilled()
|| mAutofillViewId > LAST_APP_AUTOFILL_ID) {
BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
BaseSavedState* state = new BaseSavedState(&AbsSavedState::EMPTY_STATE);
if (mStartActivityRequestWho != null) {
state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED;
if (mStartActivityRequestWho.size()) {
state->mSavedData |= BaseSavedState::START_ACTIVITY_REQUESTED_WHO_SAVED;
}
if (isAutofilled()) {
state.mSavedData |= BaseSavedState.IS_AUTOFILLED;
state->mSavedData |= BaseSavedState::IS_AUTOFILLED;
}
if (mAutofillViewId > LAST_APP_AUTOFILL_ID) {
state.mSavedData |= BaseSavedState.AUTOFILL_ID;
state->mSavedData |= BaseSavedState::AUTOFILL_ID;
}
state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
state.mIsAutofilled = isAutofilled();
state.mAutofillViewId = mAutofillViewId;
state->mStartActivityRequestWhoSaved = mStartActivityRequestWho;
state->mIsAutofilled = isAutofilled();
state->mAutofillViewId = mAutofillViewId;
return state;
}
return BaseSavedState.EMPTY_STATE;
return &BaseSavedState::EMPTY_STATE;
#endif
return nullptr;//Parcelable();
}
@ -1495,12 +1496,11 @@ void View::restoreHierarchyState(SparseArray<Parcelable*>& container){
void View::dispatchRestoreInstanceState(SparseArray<Parcelable*>& container){
if (mID != NO_ID) {
#if 0
auto it= container.find(mID);
if (it!=container.end()){//state != null) {
Parcelable state = it->second;//container.get(mID);
LOGD("View %p:%d Restoreing #",this,mID,state.c_str());
auto state= container.get(mID);
if (state != nullptr) {
LOGD("View %p:%d Restoreing #",this,mID,state);
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
onRestoreInstanceState(state);
onRestoreInstanceState(*state);
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
FATAL("Derived class did not call super.onRestoreInstanceState()");
}
@ -6447,7 +6447,7 @@ bool View::postDelayed(const std::function<void()>&what,uint32_t delay){
bool View::removeCallbacks(const Runnable& what){
View*root = getRootView();
if(root&&(root!=this))
if( root && (root!=this) )
return root->removeCallbacks(what);
return false;
}
@ -6476,7 +6476,7 @@ void View::requestLayout(){
if (mParent != nullptr && !mParent->isLayoutRequested()) {
mParent->requestLayout();
}
if (mAttachInfo && mAttachInfo->mViewRequestingLayout == this) {
if ( mAttachInfo && (mAttachInfo->mViewRequestingLayout == this) ) {
mAttachInfo->mViewRequestingLayout = nullptr;
}
}
@ -7455,4 +7455,25 @@ const std::string View::MeasureSpec::toString(int measureSpec) {
return sb.str();
}
View::BaseSavedState::BaseSavedState(Parcel& source)
:AbsSavedState(source){
mSavedData = source.readInt();
mStartActivityRequestWhoSaved = source.readString();
mIsAutofilled = source.readBoolean();
mHideHighlight = source.readBoolean();
mAutofillViewId = source.readInt();
}
View::BaseSavedState::BaseSavedState(Parcelable* superState)
:AbsSavedState(superState){
}
void View::BaseSavedState::writeToParcel(Parcel& out, int flags) {
AbsSavedState::writeToParcel(out, flags);
out.writeInt(mSavedData);
out.writeString(mStartActivityRequestWhoSaved);
out.writeBoolean(mIsAutofilled);
out.writeBoolean(mHideHighlight);
out.writeInt(mAutofillViewId);
}
}//endof namespace

View File

@ -13,6 +13,7 @@
#include <core/parcel.h>
#include <core/parcelable.h>
#include <cairomm/pattern.h>
#include <view/abssavedstate.h>
#include <view/gravity.h>
#include <view/layoutparams.h>
#include <view/rendernode.h>
@ -51,6 +52,7 @@ public:
static bool VIEW_DEBUG;
static int mViewCount;
class MeasureSpec;
class BaseSavedState;
constexpr static int DEBUG_CORNERS_COLOR = 0xFF3f7fff;
constexpr static int DEBUG_CORNERS_SIZE_DIP = 8;
constexpr static int NO_ID =-1;
@ -1313,6 +1315,24 @@ public:
static const std::string toString(int measureSpec) ;
};
using MeasureSpec=View::MeasureSpec;
class View::BaseSavedState:public AbsSavedState {
public:
static constexpr int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1;
static constexpr int IS_AUTOFILLED = 0b10;
static constexpr int AUTOFILL_ID = 0b100;
public:
// Flags that describe what data in this state is valid
int mSavedData;
std::string mStartActivityRequestWhoSaved;
bool mIsAutofilled;
bool mHideHighlight;
int mAutofillViewId;
public:
BaseSavedState(Parcel& source);
BaseSavedState(Parcelable* superState);
void writeToParcel(Parcel& out, int flags);
};
}//endof namespace cdroid
using namespace cdroid;

View File

@ -1,29 +0,0 @@
#include <widget/baseexpandablelistadapter.h>
namespace cdroid{
void BaseExpandableListAdapter::registerDataSetObserver(DataSetObserver* observer) {
//mDataSetObservable->registerObserver(observer);
auto it = std::find(mDataObservers.begin(),mDataObservers.end(),observer);
if(it != mDataObservers.end())mDataObservers.push_back(observer);
}
void BaseExpandableListAdapter::unregisterDataSetObserver(DataSetObserver* observer) {
//mDataSetObservable->unregisterObserver(observer);
auto it = std::find(mDataObservers.begin(),mDataObservers.end(),observer);
if(it != mDataObservers.end())mDataObservers.erase(it);
}
void BaseExpandableListAdapter::notifyDataSetInvalidated() {
//mDataSetObservable->notifyInvalidated();
for(auto it=mDataObservers.begin();it!=mDataObservers.end();it++)
(*it)->onInvalidated();
}
void BaseExpandableListAdapter::notifyDataSetChanged() {
//mDataSetObservable.notifyChanged();
for(auto it=mDataObservers.begin();it!=mDataObservers.end();it++)
(*it)->onChanged();
}
}/*endof namespace*/

View File

@ -1,60 +0,0 @@
#ifndef __BASEEXPANDABLE_LISTADAPTER_H__
#define __BASEEXPANDABLE_LISTADAPTER_H__
#include <widget/adapter.h>
#include <widget/expandablelistadapter.h>
namespace cdroid{
class BaseExpandableListAdapter:virtual public ExpandableListAdapter{//virtual public HeterogeneousExpandableList{
private:
//DataSetObservable* mDataSetObservable;
std::vector<DataSetObserver*>mDataObservers;
public:
void registerDataSetObserver(DataSetObserver* observer)override;
void unregisterDataSetObserver(DataSetObserver* observer)override;
virtual void notifyDataSetInvalidated();
virtual void notifyDataSetChanged();
bool areAllItemsEnabled(){
return true;
}
void onGroupCollapsed(int groupPosition)override{
}
void onGroupExpanded(int groupPosition)override{
}
int64_t getCombinedChildId(long groupId, long childId)override{
return 0x8000000000000000L | (int64_t((groupId & 0x7FFFFFFF)) << 32) | (childId & 0xFFFFFFFF);
}
int64_t getCombinedGroupId(long groupId)override{
return int64_t((groupId & 0x7FFFFFFF)) << 32;
}
bool isEmpty()override{
return getGroupCount() == 0;
}
int getChildType(int groupPosition, int childPosition) override{
return 0;
}
int getChildTypeCount()override {
return 1;
}
int getGroupType(int groupPosition)override {
return 0;
}
int getGroupTypeCount()override{
return 1;
}
};
}/*endof namespace*/
#endif/*__BASEEXPANDABLE_LISTADAPTER_H__*/

View File

@ -1,239 +0,0 @@
#include <widget/expandablelayout.h>
#include <widget/linearlayout.h>
//Referenced from
//https://github.com/cachapa/ExpandableLayout/blob/master/lib/src/main/java/net/cachapa/expandablelayout/ExpandableLayout.java
namespace cdroid{
ExpandableLayout::ExpandableLayout(int w,int h):FrameLayout(w,h){
initView();
}
ExpandableLayout::ExpandableLayout(Context* context, const AttributeSet& attrs)
:FrameLayout(context, attrs){
initView();
mDuration = attrs.getInt("duration", DEFAULT_DURATION);
mExpansion = attrs.getBoolean("expanded", false) ? 1 : 0;
mOrientation = attrs.getInt("orientation", VERTICAL);
mParallax = attrs.getFloat("parallax", 1);
mState = mExpansion == 0 ? COLLAPSED : EXPANDED;
setParallax(mParallax);
}
void ExpandableLayout::initView(){
mDuration = DEFAULT_DURATION;
mExpansion =0;
mOrientation=VERTICAL;
mParallax=1;
mState =COLLAPSED;
mAnimator = nullptr;
mInterpolator = new FastOutSlowInInterpolator();
}
ExpandableLayout::~ExpandableLayout(){
delete mInterpolator;
}
void ExpandableLayout::onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
FrameLayout::onMeasure(widthMeasureSpec, heightMeasureSpec);
const int width = getMeasuredWidth();
const int height = getMeasuredHeight();
const int size = mOrientation == LinearLayout::HORIZONTAL ? width : height;
setVisibility(mExpansion == 0 && size == 0 ? GONE : VISIBLE);
int expansionDelta = size - std::round(size * mExpansion);
if (mParallax > 0) {
float parallaxDelta = expansionDelta * mParallax;
for (int i = 0; i < getChildCount(); i++) {
View* child = getChildAt(i);
if (mOrientation == HORIZONTAL) {
int direction = -1;
if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
direction = 1;
}
child->setTranslationX(direction * parallaxDelta);
} else {
child->setTranslationY(-parallaxDelta);
}
}
}
if (mOrientation == HORIZONTAL) {
setMeasuredDimension(width - expansionDelta, height);
} else {
setMeasuredDimension(width, height - expansionDelta);
}
}
/*void ExpandableLayout::onConfigurationChanged(Configuration newConfig) {
if (mAnimator != null) {
mAnimator->cancel();
}
FrameLayout::onConfigurationChanged(newConfig);
}*/
int ExpandableLayout::getState()const{
return mState;
}
bool ExpandableLayout::isExpanded()const{
return mState == EXPANDING || mState == EXPANDED;
}
void ExpandableLayout::toggle() {
toggle(true);
}
void ExpandableLayout::toggle(bool animate) {
if (isExpanded()) {
collapse(animate);
} else {
expand(animate);
}
}
void ExpandableLayout::expand() {
expand(true);
}
void ExpandableLayout::expand(bool animate) {
setExpanded(true, animate);
}
void ExpandableLayout::collapse() {
collapse(true);
}
void ExpandableLayout::collapse(bool animate) {
setExpanded(false, animate);
}
/**
* Convenience method - same as calling setExpanded(expanded, true)
*/
void ExpandableLayout::setExpanded(bool expand) {
setExpanded(expand, true);
}
void ExpandableLayout::setExpanded(bool expand, bool animate) {
if (expand == isExpanded()) {
return;
}
int targetExpansion = expand ? 1 : 0;
if (animate) {
animateSize(targetExpansion);
} else {
setExpansion(targetExpansion);
}
}
int ExpandableLayout::getDuration()const{
return mDuration;
}
void ExpandableLayout::setInterpolator(Interpolator* interpolator) {
this->mInterpolator = interpolator;
}
void ExpandableLayout::setDuration(int duration) {
this->mDuration = duration;
}
float ExpandableLayout::getExpansion()const{
return mExpansion;
}
void ExpandableLayout::setExpansion(float expansion) {
if (this->mExpansion == expansion) {
return;
}
// Infer state from previous value
float delta = expansion - this->mExpansion;
if (expansion == 0) {
mState = COLLAPSED;
} else if (expansion == 1) {
mState = EXPANDED;
} else if (delta < 0) {
mState = COLLAPSING;
} else if (delta > 0) {
mState = EXPANDING;
}
setVisibility(mState == COLLAPSED ? GONE : VISIBLE);
this->mExpansion = expansion;
requestLayout();
if (mListener != nullptr) {
mListener(expansion, mState);
}
}
float ExpandableLayout::getParallax()const{
return mParallax;
}
void ExpandableLayout::setParallax(float parallax) {
// Make sure parallax is between 0 and 1
parallax = std::min(1.f, std::max(0.f, parallax));
this->mParallax = parallax;
}
int ExpandableLayout::getOrientation()const{
return mOrientation;
}
void ExpandableLayout::setOrientation(int orientation) {
if (orientation < 0 || orientation > 1) {
FATAL("Orientation(%d) must be either 0 (horizontal) or 1 (vertical)",orientation);
}
this->mOrientation = orientation;
}
void ExpandableLayout::setOnExpansionUpdateListener(OnExpansionUpdateListener listener) {
this->mListener = listener;
}
void ExpandableLayout::animateSize(int targetExpansion) {
mTargetExpansion = targetExpansion;
mCanceled = false;
if (mAnimator != nullptr) {
mAnimator->cancel();
//delete mAnimator;
//mAnimator = nullptr;
mAnimator->setFloatValues({mExpansion, (float)targetExpansion});
}else{
mAnimator = ValueAnimator::ofFloat({mExpansion, (float)targetExpansion});
mAnimator->setInterpolator(mInterpolator);
mAnimator->setDuration(mDuration);
mAnimator->addUpdateListener(ValueAnimator::AnimatorUpdateListener([this](ValueAnimator&anim) {
setExpansion(GET_VARIANT(anim.getAnimatedValue(),float));
}));
Animator::AnimatorListener ls;
ls.onAnimationStart=[this](Animator&anim,bool isReverse){
mState = mTargetExpansion ==0 ? COLLAPSING : EXPANDING;
};
ls.onAnimationEnd=[this](Animator&anim,bool isReverse){
if (!mCanceled) {
mState = mTargetExpansion == 0 ? COLLAPSED : EXPANDED;
setExpansion(mTargetExpansion);
}
};
ls.onAnimationCancel=[this](Animator&anim){
mCanceled = true;
};
mAnimator->addListener(ls);
}
mAnimator->start();
}
}

View File

@ -1,61 +0,0 @@
#ifndef __EXPANDABLE_LAYOUT_H__
#define __EXPANDABLE_LAYOUT_H__
#include <widget/framelayout.h>
namespace cdroid{
class ExpandableLayout:public FrameLayout{
private:
static constexpr int DEFAULT_DURATION = 300;
public:
static constexpr int COLLAPSED = 0;
static constexpr int COLLAPSING = 1;
static constexpr int EXPANDING = 2;
static constexpr int EXPANDED = 3;
static constexpr int HORIZONTAL = 0;
static constexpr int VERTICAL = 1;
DECLARE_UIEVENT(void,OnExpansionUpdateListener,float expansionFraction, int state);
private:
int mDuration = DEFAULT_DURATION;
float mParallax;
float mExpansion;
int mOrientation;
int mState;
float mTargetExpansion;
bool mCanceled;
Interpolator* mInterpolator;// = new FastOutSlowInInterpolator();
ValueAnimator* mAnimator;
OnExpansionUpdateListener mListener;
private:
void initView();
void animateSize(int targetExpansion);
protected:
void onMeasure(int widthMeasureSpec, int heightMeasureSpec)override;
public:
ExpandableLayout(int w,int h);
ExpandableLayout(Context* context,const AttributeSet& attrs);
~ExpandableLayout();
int getState()const;
bool isExpanded()const;
void toggle();
void toggle(bool animate);
void expand();
void expand(bool animate);
void collapse();
void collapse(bool animate);
void setExpanded(bool expand);
void setExpanded(bool expand, bool animate);
int getDuration()const;
void setDuration(int duration);
void setInterpolator(Interpolator* interpolator);
float getExpansion()const;
void setExpansion(float expansion);
float getParallax()const;
void setParallax(float parallax);
int getOrientation()const;
void setOrientation(int orientation);
void setOnExpansionUpdateListener(OnExpansionUpdateListener listener);
};
}/*endof namespace*/
#endif

View File

@ -1,322 +0,0 @@
#ifndef __EXPANDABLE_LISTADAPTER_H__
#define __EXPANDABLE_LISTADAPTER_H__
namespace cdroid{
class HeterogeneousExpandableList {
public:
/**
* Get the type of group View that will be created by
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* . for the specified group item.
*
* @param groupPosition the position of the group for which the type should be returned.
* @return An integer representing the type of group View. Two group views should share the same
* type if one can be converted to the other in
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* . Note: Integers must be in the range 0 to {@link #getGroupTypeCount} - 1.
* {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
* @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
* @see #getGroupTypeCount()
*/
virtual int getGroupType(int groupPosition)=0;
/**
* Get the type of child View that will be created by
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
* for the specified child item.
*
* @param groupPosition the position of the group that the child resides in
* @param childPosition the position of the child with respect to other children in the group
* @return An integer representing the type of child View. Two child views should share the same
* type if one can be converted to the other in
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
* Note: Integers must be in the range 0 to {@link #getChildTypeCount} - 1.
* {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
* @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
* @see #getChildTypeCount()
*/
virtual int getChildType(int groupPosition, int childPosition)=0;
/**
* <p>
* Returns the number of types of group Views that will be created by
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* . Each type represents a set of views that can be converted in
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* . If the adapter always returns the same type of View for all group items, this method should
* return 1.
* </p>
* This method will only be called when the adapter is set on the {@link AdapterView}.
*
* @return The number of types of group Views that will be created by this adapter.
* @see #getChildTypeCount()
* @see #getGroupType(int)
*/
virtual int getGroupTypeCount()=0;
/**
* <p>
* Returns the number of types of child Views that will be created by
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
* . Each type represents a set of views that can be converted in
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
* , for any group. If the adapter always returns the same type of View for
* all child items, this method should return 1.
* </p>
* This method will only be called when the adapter is set on the {@link AdapterView}.
*
* @return The total number of types of child Views that will be created by this adapter.
* @see #getGroupTypeCount()
* @see #getChildType(int, int)
*/
virtual int getChildTypeCount()=0;
};
class ExpandableListAdapter {
public:
/**
* @see Adapter#registerDataSetObserver(DataSetObserver)
*/
virtual void registerDataSetObserver(DataSetObserver* observer)=0;
/**
* @see Adapter#unregisterDataSetObserver(DataSetObserver)
*/
virtual void unregisterDataSetObserver(DataSetObserver* observer)=0;
/**
* Gets the number of groups.
*
* @return the number of groups
*/
virtual int getGroupCount()=0;
/**
* Gets the number of children in a specified group.
*
* @param groupPosition the position of the group for which the children
* count should be returned
* @return the children count in the specified group
*/
virtual int getChildrenCount(int groupPosition)=0;
/**
* Gets the data associated with the given group.
*
* @param groupPosition the position of the group
* @return the data child for the specified group
*/
virtual void* getGroup(int groupPosition)=0;
/**
* Get the type of group View that will be created by
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* . for the specified group item.
*
* @param groupPosition the position of the group for which the type should be returned.
* @return An integer representing the type of group View. Two group views should share the same
* type if one can be converted to the other in
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* . Note: Integers must be in the range 0 to {@link #getGroupTypeCount} - 1.
* {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
* @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
* @see #getGroupTypeCount()
*/
virtual int getGroupType(int groupPosition)=0;/*====*/
/**
* <p>
* Returns the number of types of group Views that will be created by
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* . Each type represents a set of views that can be converted in
* {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
* . If the adapter always returns the same type of View for all group items, this method should
* return 1.
* </p>
* This method will only be called when the adapter is set on the {@link AdapterView}.
*
* @return The number of types of group Views that will be created by this adapter.
* @see #getChildTypeCount()
* @see #getGroupType(int)
*/
virtual int getGroupTypeCount()=0;/*====*/
/**
* Gets the data associated with the given child within the given group.
*
* @param groupPosition the position of the group that the child resides in
* @param childPosition the position of the child with respect to other
* children in the group
* @return the data of the child
*/
virtual void* getChild(int groupPosition, int childPosition)=0;
/**
* Get the type of child View that will be created by
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
* for the specified child item.
*
* @param groupPosition the position of the group that the child resides in
* @param childPosition the position of the child with respect to other children in the group
* @return An integer representing the type of child View. Two child views should share the same
* type if one can be converted to the other in
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
* Note: Integers must be in the range 0 to {@link #getChildTypeCount} - 1.
* {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
* @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
* @see #getChildTypeCount()
*/
virtual int getChildType(int groupPosition, int childPosition)=0;/*===*/
/**
* <p>
* Returns the number of types of child Views that will be created by
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
* . Each type represents a set of views that can be converted in
* {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
* , for any group. If the adapter always returns the same type of View for
* all child items, this method should return 1.
* </p>
* This method will only be called when the adapter is set on the {@link AdapterView}.
*
* @return The total number of types of child Views that will be created by this adapter.
* @see #getGroupTypeCount()
* @see #getChildType(int, int)
*/
virtual int getChildTypeCount()=0;/*===*/
/**
* Gets the ID for the group at the given position. This group ID must be
* unique across groups. The combined ID (see
* {@link #getCombinedGroupId(long)}) must be unique across ALL items
* (groups and all children).
*
* @param groupPosition the position of the group for which the ID is wanted
* @return the ID associated with the group
*/
virtual long getGroupId(int groupPosition)=0;
/**
* Gets the ID for the given child within the given group. This ID must be
* unique across all children within the group. The combined ID (see
* {@link #getCombinedChildId(long, long)}) must be unique across ALL items
* (groups and all children).
*
* @param groupPosition the position of the group that contains the child
* @param childPosition the position of the child within the group for which
* the ID is wanted
* @return the ID associated with the child
*/
virtual long getChildId(int groupPosition, int childPosition)=0;
/**
* Indicates whether the child and group IDs are stable across changes to the
* underlying data.
*
* @return whether or not the same ID always refers to the same object
* @see Adapter#hasStableIds()
*/
virtual bool hasStableIds()=0;
/**
* Gets a View that displays the given group. This View is only for the
* group--the Views for the group's children will be fetched using
* {@link #getChildView(int, int, boolean, View, ViewGroup)}.
*
* @param groupPosition the position of the group for which the View is
* returned
* @param isExpanded whether the group is expanded or collapsed
* @param convertView the old view to reuse, if possible. You should check
* that this view is non-null and of an appropriate type before
* using. If it is not possible to convert this view to display
* the correct data, this method can create a new view. It is not
* guaranteed that the convertView will have been previously
* created by
* {@link #getGroupView(int, boolean, View, ViewGroup)}.
* @param parent the parent that this view will eventually be attached to
* @return the View corresponding to the group at the specified position
*/
virtual View* getGroupView(int groupPosition, bool isExpanded, View* convertView, ViewGroup* parent)=0;
/**
* Gets a View that displays the data for the given child within the given
* group.
*
* @param groupPosition the position of the group that contains the child
* @param childPosition the position of the child (for which the View is
* returned) within the group
* @param isLastChild Whether the child is the last child within the group
* @param convertView the old view to reuse, if possible. You should check
* that this view is non-null and of an appropriate type before
* using. If it is not possible to convert this view to display
* the correct data, this method can create a new view. It is not
* guaranteed that the convertView will have been previously
* created by
* {@link #getChildView(int, int, boolean, View, ViewGroup)}.
* @param parent the parent that this view will eventually be attached to
* @return the View corresponding to the child at the specified position
*/
virtual View* getChildView(int groupPosition, int childPosition, bool isLastChild,
View* convertView, ViewGroup* parent)=0;
/**
* Whether the child at the specified position is selectable.
*
* @param groupPosition the position of the group that contains the child
* @param childPosition the position of the child within the group
* @return whether the child is selectable.
*/
virtual bool isChildSelectable(int groupPosition, int childPosition)=0;
/**
* @see ListAdapter#areAllItemsEnabled()
*/
virtual bool areAllItemsEnabled()=0;
/**
* @see ListAdapter#isEmpty()
*/
virtual bool isEmpty()=0;
/**
* Called when a group is expanded.
*
* @param groupPosition The group being expanded.
*/
virtual void onGroupExpanded(int groupPosition)=0;
/**
* Called when a group is collapsed.
*
* @param groupPosition The group being collapsed.
*/
virtual void onGroupCollapsed(int groupPosition)=0;
/**
* Gets an ID for a child that is unique across any item (either group or
* child) that is in this list. Expandable lists require each item (group or
* child) to have a unique ID among all children and groups in the list.
* This method is responsible for returning that unique ID given a child's
* ID and its group's ID. Furthermore, if {@link #hasStableIds()} is true, the
* returned ID must be stable as well.
*
* @param groupId The ID of the group that contains this child.
* @param childId The ID of the child.
* @return The unique (and possibly stable) ID of the child across all
* groups and children in this list.
*/
virtual int64_t getCombinedChildId(long groupId, long childId)=0;
/**
* Gets an ID for a group that is unique across any item (either group or
* child) that is in this list. Expandable lists require each item (group or
* child) to have a unique ID among all children and groups in the list.
* This method is responsible for returning that unique ID given a group's
* ID. Furthermore, if {@link #hasStableIds()} is true, the returned ID must be
* stable as well.
*
* @param groupId The ID of the group
* @return The unique (and possibly stable) ID of the group across all
* groups and children in this list.
*/
virtual int64_t getCombinedGroupId(long groupId)=0;
};
}/*endof namespace*/
#endif/*__EXPANDABLE_LISTADAPTER_H__*/

View File

@ -1,610 +0,0 @@
#include <widget/expandablelistconnector.h>
#include <widget/adapterview.h>
namespace cdroid{
ExpandableListConnector::ExpandableListConnector(ExpandableListAdapter* expandableListAdapter){
mExpandableListAdapter = nullptr;
mTotalExpChildrenCount = 0;
mDataSetObserver = new MyDataSetObserver(this);
setExpandableListAdapter(expandableListAdapter);
}
ExpandableListConnector::~ExpandableListConnector(){
delete mDataSetObserver;
}
void ExpandableListConnector::setExpandableListAdapter(ExpandableListAdapter* expandableListAdapter) {
if (mExpandableListAdapter ) {
mExpandableListAdapter->unregisterDataSetObserver(mDataSetObserver);
}
mExpandableListAdapter = expandableListAdapter;
expandableListAdapter->registerDataSetObserver(mDataSetObserver);
}
ExpandableListConnector::PositionMetadata* ExpandableListConnector::getUnflattenedPos(int flPos) const{
/* Keep locally since frequent use */
const std::vector<GroupMetadata*>& egml = mExpGroupMetadataList;
const int numExpGroups = egml.size();
/* Binary search variables */
int leftExpGroupIndex = 0;
int rightExpGroupIndex = numExpGroups - 1;
int midExpGroupIndex = 0;
GroupMetadata* midExpGm;
if (numExpGroups == 0) {
return PositionMetadata::obtain(flPos, ExpandableListPosition::GROUP, flPos, -1, nullptr, 0);
}
while (leftExpGroupIndex <= rightExpGroupIndex) {
midExpGroupIndex = (rightExpGroupIndex - leftExpGroupIndex) / 2 + leftExpGroupIndex;
midExpGm = egml.at(midExpGroupIndex);
if (flPos > midExpGm->lastChildFlPos) {
leftExpGroupIndex = midExpGroupIndex + 1;
} else if (flPos < midExpGm->flPos) {
rightExpGroupIndex = midExpGroupIndex - 1;
} else if (flPos == midExpGm->flPos) {
return PositionMetadata::obtain(flPos, ExpandableListPosition::GROUP,
midExpGm->gPos, -1, midExpGm, midExpGroupIndex);
} else if (flPos <= midExpGm->lastChildFlPos
/* && flPos > midGm.flPos as deduced from previous
* conditions */) {
const int childPos = flPos - (midExpGm->flPos + 1);
return PositionMetadata::obtain(flPos, ExpandableListPosition::CHILD,
midExpGm->gPos, childPos, midExpGm, midExpGroupIndex);
}
}
int insertPosition = 0;
/** What is its group position in the list of all groups? */
int groupPos = 0;
if (leftExpGroupIndex > midExpGroupIndex) {
const GroupMetadata* leftExpGm = egml.at(leftExpGroupIndex-1);
insertPosition = leftExpGroupIndex;
groupPos = (flPos - leftExpGm->lastChildFlPos) + leftExpGm->gPos;
} else if (rightExpGroupIndex < midExpGroupIndex) {
const GroupMetadata* rightExpGm = egml.at(++rightExpGroupIndex);
insertPosition = rightExpGroupIndex;
groupPos = rightExpGm->gPos - (rightExpGm->flPos - flPos);
} else {
// TODO: clean exit
FATAL("Unknown state");
}
return PositionMetadata::obtain(flPos, ExpandableListPosition::GROUP, groupPos, -1,
nullptr, insertPosition);
}
ExpandableListConnector::PositionMetadata* ExpandableListConnector::getFlattenedPos(const ExpandableListPosition& pos) {
const std::vector<GroupMetadata*>& egml = mExpGroupMetadataList;
const int numExpGroups = egml.size();
/* Binary search variables */
int leftExpGroupIndex = 0;
int rightExpGroupIndex = numExpGroups - 1;
int midExpGroupIndex = 0;
GroupMetadata* midExpGm;
if (numExpGroups == 0) {
return PositionMetadata::obtain(pos.groupPos, pos.type, pos.groupPos, pos.childPos, nullptr, 0);
}
while (leftExpGroupIndex <= rightExpGroupIndex) {
midExpGroupIndex = (rightExpGroupIndex - leftExpGroupIndex)/2 + leftExpGroupIndex;
midExpGm = egml.at(midExpGroupIndex);
if (pos.groupPos > midExpGm->gPos) {
leftExpGroupIndex = midExpGroupIndex + 1;
} else if (pos.groupPos < midExpGm->gPos) {
rightExpGroupIndex = midExpGroupIndex - 1;
} else if (pos.groupPos == midExpGm->gPos) {
if (pos.type == ExpandableListPosition::GROUP) {
/* If it's a group, give them this matched group's flPos */
return PositionMetadata::obtain(midExpGm->flPos, pos.type,
pos.groupPos, pos.childPos, midExpGm, midExpGroupIndex);
} else if (pos.type == ExpandableListPosition::CHILD) {
/* If it's a child, calculate the flat list pos */
return PositionMetadata::obtain(midExpGm->flPos + pos.childPos
+ 1, pos.type, pos.groupPos, pos.childPos,
midExpGm, midExpGroupIndex);
} else {
return nullptr;
}
}
}
if (pos.type != ExpandableListPosition::GROUP) {
/* If it isn't a group, return null */
return nullptr;
}
if (leftExpGroupIndex > midExpGroupIndex) {
const GroupMetadata* leftExpGm = egml.at(leftExpGroupIndex-1);
const int flPos = leftExpGm->lastChildFlPos + (pos.groupPos - leftExpGm->gPos);
return PositionMetadata::obtain(flPos, pos.type, pos.groupPos,
pos.childPos, nullptr, leftExpGroupIndex);
} else if (rightExpGroupIndex < midExpGroupIndex) {
const GroupMetadata* rightExpGm = egml.at(++rightExpGroupIndex);
const int flPos = rightExpGm->flPos - (rightExpGm->gPos - pos.groupPos);
return PositionMetadata::obtain(flPos, pos.type, pos.groupPos,
pos.childPos, nullptr, rightExpGroupIndex);
} else {
return nullptr;
}
}
bool ExpandableListConnector::areAllItemsEnabled() {
return mExpandableListAdapter->areAllItemsEnabled();
}
bool ExpandableListConnector::isEnabled(int flatListPos) {
PositionMetadata* metadata = getUnflattenedPos(flatListPos);
ExpandableListPosition* pos = metadata->position;
bool retValue;
if (pos->type == ExpandableListPosition::CHILD) {
retValue = mExpandableListAdapter->isChildSelectable(pos->groupPos, pos->childPos);
} else {
// Groups are always selectable
retValue = true;
}
metadata->recycle();
return retValue;
}
int ExpandableListConnector::getCount()const{
/* Total count for the list view is the number groups plus the
* number of children from currently expanded groups (a value we keep
* cached in this class)*/
return mExpandableListAdapter->getGroupCount() + mTotalExpChildrenCount;
}
void* ExpandableListConnector::getItem(int flatListPos) const{
PositionMetadata* posMetadata = getUnflattenedPos(flatListPos);
void* retValue;/*Object*/
if (posMetadata->position->type == ExpandableListPosition::GROUP) {
retValue = mExpandableListAdapter->getGroup(posMetadata->position->groupPos);
} else if (posMetadata->position->type == ExpandableListPosition::CHILD) {
retValue = mExpandableListAdapter->getChild(posMetadata->position->groupPos,
posMetadata->position->childPos);
} else {
// TODO: clean exit
FATAL("Flat list position is of unknown type");
}
posMetadata->recycle();
return retValue;
}
long ExpandableListConnector::getItemId(int flatListPos) {
PositionMetadata* posMetadata = getUnflattenedPos(flatListPos);
const long groupId = mExpandableListAdapter->getGroupId(posMetadata->position->groupPos);
long retValue;
if (posMetadata->position->type == ExpandableListPosition::GROUP) {
retValue = mExpandableListAdapter->getCombinedGroupId(groupId);
} else if (posMetadata->position->type == ExpandableListPosition::CHILD) {
const long childId = mExpandableListAdapter->getChildId(posMetadata->position->groupPos,
posMetadata->position->childPos);
retValue = mExpandableListAdapter->getCombinedChildId(groupId, childId);
} else {
// TODO: clean exit
FATAL("Flat list position is of unknown type");
}
posMetadata->recycle();
return retValue;
}
View* ExpandableListConnector::getView(int flatListPos, View* convertView, ViewGroup* parent){
View* retValue;
PositionMetadata* posMetadata = getUnflattenedPos(flatListPos);
if (posMetadata->position->type == ExpandableListPosition::GROUP) {
retValue = mExpandableListAdapter->getGroupView(posMetadata->position->groupPos,
posMetadata->isExpanded(), convertView, parent);
} else if (posMetadata->position->type == ExpandableListPosition::CHILD) {
const bool isLastChild = posMetadata->groupMetadata->lastChildFlPos == flatListPos;
retValue = mExpandableListAdapter->getChildView(posMetadata->position->groupPos,
posMetadata->position->childPos, isLastChild, convertView, parent);
} else {
// TODO: clean exit
FATAL("Flat list position is of unknown type");
}
posMetadata->recycle();
return retValue;
}
int ExpandableListConnector::getItemViewType(int flatListPos)const {
PositionMetadata* metadata = getUnflattenedPos(flatListPos);
const ExpandableListPosition* pos = metadata->position;
int retValue;
auto adapter = mExpandableListAdapter;
if (pos->type == ExpandableListPosition::GROUP) {
retValue = adapter->getGroupType(pos->groupPos);
} else {
const int childType = adapter->getChildType(pos->groupPos, pos->childPos);
retValue = adapter->getGroupTypeCount() + childType;
}
metadata->recycle();
return retValue;
}
int ExpandableListConnector::getViewTypeCount()const{
auto adapter = mExpandableListAdapter;
return adapter->getGroupTypeCount() + adapter->getChildTypeCount();
}
bool ExpandableListConnector::hasStableIds() const{
return mExpandableListAdapter->hasStableIds();
}
void ExpandableListConnector::refreshExpGroupMetadataList(bool forceChildrenCountRefresh, bool syncGroupPositions){
std::vector<GroupMetadata*>& egml = mExpGroupMetadataList;
int egmlSize = egml.size();
int curFlPos = 0;
/* Update child count as we go through */
mTotalExpChildrenCount = 0;
if (syncGroupPositions) {
// We need to check whether any groups have moved positions
bool positionsChanged = false;
for (int i = egmlSize - 1; i >= 0; i--) {
GroupMetadata* curGm = egml.at(i);
int newGPos = findGroupPosition(curGm->gId, curGm->gPos);
if (newGPos != curGm->gPos) {
if (newGPos == AdapterView::INVALID_POSITION) {
// Doh, just remove it from the list of expanded groups
egml.erase(egml.begin()+i);//remove(i);
egmlSize--;
}
curGm->gPos = newGPos;
if (!positionsChanged) positionsChanged = true;
}
}
if (positionsChanged) {
// At least one group changed positions, so re-sort
//Collections.sort(egml);
std::sort(egml.begin(),egml.end(), [](GroupMetadata*lhs,GroupMetadata*rhs)->int{
return lhs->gPos-rhs->gPos;
});
}
}
int gChildrenCount;
int lastGPos = 0;
for (int i = 0; i < egmlSize; i++) {
/* Store in local variable since we'll access freq */
GroupMetadata* curGm = egml.at(i);
/* Get the number of children, try to refrain from calling
* another class's method unless we have to (so do a subtraction) */
if ((curGm->lastChildFlPos == GroupMetadata::REFRESH) || forceChildrenCountRefresh) {
gChildrenCount = mExpandableListAdapter->getChildrenCount(curGm->gPos);
} else {
/* Num children for this group is its last child's fl pos minus
* the group's fl pos */
gChildrenCount = curGm->lastChildFlPos - curGm->flPos;
}
/* Update */
mTotalExpChildrenCount += gChildrenCount;
curFlPos += (curGm->gPos - lastGPos);
lastGPos = curGm->gPos;
/* Update the flat list positions, and the current flat list pos */
curGm->flPos = curFlPos;
curFlPos += gChildrenCount;
curGm->lastChildFlPos = curFlPos;
}
}
bool ExpandableListConnector::collapseGroup(int groupPos) {
ExpandableListPosition* elGroupPos = ExpandableListPosition::obtain(
ExpandableListPosition::GROUP, groupPos, -1, -1);
PositionMetadata* pm = getFlattenedPos(*elGroupPos);
elGroupPos->recycle();
if (pm == nullptr) return false;
bool retValue = collapseGroup(*pm);
pm->recycle();
return retValue;
}
bool ExpandableListConnector::collapseGroup(PositionMetadata& posMetadata) {
/*
* Collapsing requires removal from mExpGroupMetadataList
*/
/*
* If it is null, it must be already collapsed. This group metadata
* object should have been set from the search that returned the
* position metadata object.
*/
if (posMetadata.groupMetadata == nullptr) return false;
// Remove the group from the list of expanded groups
auto it = std::find(mExpGroupMetadataList.begin(),mExpGroupMetadataList.end(),posMetadata.groupMetadata);
mExpGroupMetadataList.erase(it);//remove(posMetadata.groupMetadata);
// Refresh the metadata
refreshExpGroupMetadataList(false, false);
// Notify of change
notifyDataSetChanged();
// Give the callback
mExpandableListAdapter->onGroupCollapsed(posMetadata.groupMetadata->gPos);
return true;
}
bool ExpandableListConnector::expandGroup(int groupPos) {
ExpandableListPosition* elGroupPos = ExpandableListPosition::obtain(
ExpandableListPosition::GROUP, groupPos, -1, -1);
PositionMetadata* pm = getFlattenedPos(*elGroupPos);
elGroupPos->recycle();
const bool retValue = expandGroup(*pm);
pm->recycle();
return retValue;
}
bool ExpandableListConnector::expandGroup(PositionMetadata& posMetadata) {
/*
* Expanding requires insertion into the mExpGroupMetadataList
*/
if (posMetadata.position->groupPos < 0) {
// TODO clean exit
FATAL("Need group");
}
if (mMaxExpGroupCount == 0) return false;
// Check to see if it's already expanded
if (posMetadata.groupMetadata != nullptr) return false;
/* Restrict number of expanded groups to mMaxExpGroupCount */
if (mExpGroupMetadataList.size() >= mMaxExpGroupCount) {
/* Collapse a group */
// TODO: Collapse something not on the screen instead of the first one?
// TODO: Could write overloaded function to take GroupMetadata to collapse
GroupMetadata* collapsedGm = mExpGroupMetadataList.at(0);
auto it = std::find(mExpGroupMetadataList.begin(),mExpGroupMetadataList.end(),collapsedGm);
int collapsedIndex = it - mExpGroupMetadataList.begin();//mExpGroupMetadataList.indexOf(collapsedGm);
collapseGroup(collapsedGm->gPos);
/* Decrement index if it is after the group we removed */
if (posMetadata.groupInsertIndex > collapsedIndex) {
posMetadata.groupInsertIndex--;
}
}
GroupMetadata* expandedGm = GroupMetadata::obtain(GroupMetadata::REFRESH,GroupMetadata::REFRESH,
posMetadata.position->groupPos, mExpandableListAdapter->getGroupId(posMetadata.position->groupPos));
mExpGroupMetadataList.insert(mExpGroupMetadataList.begin() + posMetadata.groupInsertIndex, expandedGm);
// Refresh the metadata
refreshExpGroupMetadataList(false, false);
// Notify of change
notifyDataSetChanged();
// Give the callback
mExpandableListAdapter->onGroupExpanded(expandedGm->gPos);
return true;
}
bool ExpandableListConnector::isGroupExpanded(int groupPosition) {
GroupMetadata* groupMetadata;
for (int i = mExpGroupMetadataList.size() - 1; i >= 0; i--) {
groupMetadata = mExpGroupMetadataList.at(i);
if (groupMetadata->gPos == groupPosition) {
return true;
}
}
return false;
}
void ExpandableListConnector::setMaxExpGroupCount(int maxExpGroupCount) {
mMaxExpGroupCount = maxExpGroupCount;
}
ExpandableListAdapter* ExpandableListConnector::getAdapter() {
return mExpandableListAdapter;
}
Filter* ExpandableListConnector::getFilter() {
ExpandableListAdapter* adapter = getAdapter();
if (dynamic_cast<Filterable*>(adapter)) {
return ((Filterable*) adapter)->getFilter();
} else {
return nullptr;
}
}
std::vector<ExpandableListConnector::GroupMetadata*>& ExpandableListConnector::getExpandedGroupMetadataList() {
return mExpGroupMetadataList;
}
void ExpandableListConnector::setExpandedGroupMetadataList(std::vector<GroupMetadata*>& expandedGroupMetadataList) {
if (mExpandableListAdapter == nullptr) {
return;
}
// Make sure our current data set is big enough for the previously
// expanded groups, if not, ignore this request
const int numGroups = mExpandableListAdapter->getGroupCount();
for (int i = expandedGroupMetadataList.size() - 1; i >= 0; i--) {
if (expandedGroupMetadataList.at(i)->gPos >= numGroups) {
// Doh, for some reason the client doesn't have some of the groups
return;
}
}
mExpGroupMetadataList = expandedGroupMetadataList;
refreshExpGroupMetadataList(true, false);
}
bool ExpandableListConnector::isEmpty() {
ExpandableListAdapter* adapter = getAdapter();
return adapter ? adapter->isEmpty() : true;
}
int ExpandableListConnector::findGroupPosition(long groupIdToMatch, int seedGroupPosition) {
const int count = mExpandableListAdapter->getGroupCount();
if (count == 0) {
return AdapterView::INVALID_POSITION;
}
// If there isn't a selection don't hunt for it
if (groupIdToMatch == AdapterView::INVALID_ROW_ID) {
return AdapterView::INVALID_POSITION;
}
// Pin seed to reasonable values
seedGroupPosition = std::max(0, seedGroupPosition);
seedGroupPosition = std::min(count - 1, seedGroupPosition);
long endTime = SystemClock::uptimeMillis() + AdapterView::SYNC_MAX_DURATION_MILLIS;
long rowId;
// first position scanned so far
int first = seedGroupPosition;
// last position scanned so far
int last = seedGroupPosition;
// True if we should move down on the next iteration
bool next = false;
// True when we have looked at the first item in the data
bool hitFirst;
// True when we have looked at the last item in the data
bool hitLast;
// Get the item ID locally (instead of getItemIdAtPosition), so
// we need the adapter
ExpandableListAdapter* adapter = getAdapter();
if (adapter == nullptr) {
return AdapterView::INVALID_POSITION;
}
while (SystemClock::uptimeMillis() <= endTime) {
rowId = adapter->getGroupId(seedGroupPosition);
if (rowId == groupIdToMatch) {
// Found it!
return seedGroupPosition;
}
hitLast = last == count - 1;
hitFirst = first == 0;
if (hitLast && hitFirst) {
// Looked at everything
break;
}
if (hitFirst || (next && !hitLast)) {
// Either we hit the top, or we are trying to move down
last++;
seedGroupPosition = last;
// Try going up next time
next = false;
} else if (hitLast || (!next && !hitFirst)) {
// Either we hit the bottom, or we are trying to move up
first--;
seedGroupPosition = first;
// Try going down next time
next = true;
}
}
return AdapterView::INVALID_POSITION;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
std::queue<ExpandableListConnector::PositionMetadata*> ExpandableListConnector::PositionMetadata::sPool;
ExpandableListConnector::GroupMetadata*
ExpandableListConnector::GroupMetadata::obtain(int flPos, int lastChildFlPos, int gPos, long gId) {
GroupMetadata* gm = new GroupMetadata();
gm->flPos = flPos;
gm->lastChildFlPos = lastChildFlPos;
gm->gPos = gPos;
gm->gId = gId;
return gm;
}
void ExpandableListConnector::PositionMetadata::resetState() {
if (position != nullptr) {
position->recycle();
position = nullptr;
}
groupMetadata = nullptr;
groupInsertIndex = 0;
}
ExpandableListConnector::PositionMetadata::PositionMetadata() {
}
ExpandableListConnector::PositionMetadata*
ExpandableListConnector::PositionMetadata::obtain(int flatListPos, int type, int groupPos,
int childPos, GroupMetadata* groupMetadata, int groupInsertIndex) {
PositionMetadata* pm = getRecycledOrCreate();
pm->position = ExpandableListPosition::obtain(type, groupPos, childPos, flatListPos);
pm->groupMetadata = groupMetadata;
pm->groupInsertIndex = groupInsertIndex;
return pm;
}
ExpandableListConnector::PositionMetadata* ExpandableListConnector::PositionMetadata::getRecycledOrCreate() {
PositionMetadata* pm;
if (sPool.size() > 0) {
pm = sPool.front();
sPool.pop();
} else {
return new PositionMetadata();
}
pm->resetState();
return pm;
}
void ExpandableListConnector::PositionMetadata::recycle(){
resetState();
if (sPool.size() < MAX_POOL_SIZE) {
sPool.push((PositionMetadata*)this);
}
}
bool ExpandableListConnector::PositionMetadata::isExpanded() const{
return groupMetadata != nullptr;
}
}/*endof namespace*/

View File

@ -1,123 +0,0 @@
#ifndef __EXPANDABLE_LIST_CONNECTIOR_H__
#define __EXPANDABLE_LIST_CONNECTIOR_H__
#include <queue>
#include <widget/adapter.h>
#include <widget/filterable.h>
#include <widget/expandablelistposition.h>
#include <widget/expandablelistadapter.h>
namespace cdroid{
class ExpandableListConnector:public BaseAdapter,public Filterable{
protected:
class MyDataSetObserver:public DataSetObserver {
ExpandableListConnector*mConnector;
public:
MyDataSetObserver(ExpandableListConnector*connector){
mConnector = connector;
}
void onChanged() {
mConnector->refreshExpGroupMetadataList(true, true);
mConnector->notifyDataSetChanged();
}
void onInvalidated() {
mConnector->refreshExpGroupMetadataList(true, true);
mConnector->notifyDataSetInvalidated();
}
void clearSavedState()override{}
};
public:
class GroupMetadata{
public:
static constexpr int REFRESH = -1;
/** This group's flat list position */
int flPos;
/* firstChildFlPos isn't needed since it's (flPos + 1) */
/* This group's last child's flat list position, so basically
* the range of this group in the flat list */
int lastChildFlPos;
/* This group's group position */
int gPos;
/* This group's id */
long gId;
public:
static GroupMetadata* obtain(int flPos, int lastChildFlPos, int gPos, long gId);
};
class PositionMetadata {
private:
static constexpr int MAX_POOL_SIZE = 5;
static std::queue<PositionMetadata*> sPool;
/** Data type to hold the position and its type (child/group) */
void resetState();
PositionMetadata();
public:
ExpandableListPosition* position;
/* Link back to the expanded GroupMetadata for this group. Useful for
* removing the group from the list of expanded groups inside the
* connector when we collapse the group, and also as a check to see if
* the group was expanded or collapsed (this will be null if the group
* is collapsed since we don't keep that group's metadata)*/
GroupMetadata* groupMetadata;
/* For groups that are collapsed, we use this as the index (in
* mExpGroupMetadataList) to insert this group when we are expanding
* this group.*/
int groupInsertIndex;
static PositionMetadata* obtain(int flatListPos, int type, int groupPos,
int childPos, GroupMetadata* groupMetadata, int groupInsertIndex);
static PositionMetadata* getRecycledOrCreate() ;
void recycle();
bool isExpanded()const;
};
private:
ExpandableListAdapter* mExpandableListAdapter;
/**
* List of metadata for the currently expanded groups. The metadata consists
* of data essential for efficiently translating between flat list positions
* and group/child positions. See {@link GroupMetadata}.
*/
std::vector<GroupMetadata*> mExpGroupMetadataList;
/** The number of children from all currently expanded groups */
int mTotalExpChildrenCount;
/** The maximum number of allowable expanded groups. Defaults to 'no limit' */
int mMaxExpGroupCount = INT_MAX;
/** Change observer used to have ExpandableListAdapter changes pushed to us */
DataSetObserver* mDataSetObserver;
private:
void refreshExpGroupMetadataList(bool forceChildrenCountRefresh, bool syncGroupPositions);
public:
ExpandableListConnector(ExpandableListAdapter* expandableListAdapter);
~ExpandableListConnector();
void setExpandableListAdapter(ExpandableListAdapter* expandableListAdapter);
PositionMetadata* getUnflattenedPos( int flPos)const;/*protected*/
PositionMetadata* getFlattenedPos(const ExpandableListPosition& pos);/*proteced*/
bool areAllItemsEnabled();
bool isEnabled(int flatListPos);
int getCount()const;
void*getItem(int flatListPos)const;
long getItemId(int flatListPos);
View* getView(int flatListPos, View* convertView, ViewGroup* parent);
int getItemViewType(int flatListPos)const override;
int getViewTypeCount()const override;
bool hasStableIds()const override;
bool collapseGroup(int groupPos);
bool collapseGroup(PositionMetadata& posMetadata);
bool expandGroup(int groupPos);
bool expandGroup(PositionMetadata& posMetadata);
bool isGroupExpanded(int groupPosition);
void setMaxExpGroupCount(int maxExpGroupCount);
ExpandableListAdapter* getAdapter();
Filter* getFilter();
std::vector<GroupMetadata*>& getExpandedGroupMetadataList();
void setExpandedGroupMetadataList(std::vector<GroupMetadata*>& expandedGroupMetadataList);
bool isEmpty();
int findGroupPosition(long groupIdToMatch, int seedGroupPosition);
};
}/*endof namespace*/
#endif

View File

@ -1,77 +0,0 @@
#include <widget/expandablelistposition.h>
#include <widget/expandablelistview.h>
namespace cdroid{
std::queue<ExpandableListPosition*> ExpandableListPosition::sPool;
void ExpandableListPosition::resetState() {
groupPos = 0;
childPos = 0;
flatListPos = 0;
type = 0;
}
ExpandableListPosition::ExpandableListPosition() {
}
long ExpandableListPosition::getPackedPosition() {
if (type == CHILD) return ExpandableListView::getPackedPositionForChild(groupPos, childPos);
else return ExpandableListView::getPackedPositionForGroup(groupPos);
}
ExpandableListPosition* ExpandableListPosition::obtainGroupPosition(int groupPosition) {
return obtain(GROUP, groupPosition, 0, 0);
}
ExpandableListPosition* ExpandableListPosition::obtainChildPosition(int groupPosition, int childPosition) {
return obtain(CHILD, groupPosition, childPosition, 0);
}
ExpandableListPosition* ExpandableListPosition::obtainPosition(long packedPosition) {
if (packedPosition == ExpandableListView::PACKED_POSITION_VALUE_NULL) {
return nullptr;
}
ExpandableListPosition* elp = getRecycledOrCreate();
elp->groupPos = ExpandableListView::getPackedPositionGroup(packedPosition);
if (ExpandableListView::getPackedPositionType(packedPosition) ==
ExpandableListView::PACKED_POSITION_TYPE_CHILD) {
elp->type = CHILD;
elp->childPos = ExpandableListView::getPackedPositionChild(packedPosition);
} else {
elp->type = GROUP;
}
return elp;
}
ExpandableListPosition* ExpandableListPosition::obtain(int type, int groupPos, int childPos, int flatListPos) {
ExpandableListPosition* elp = getRecycledOrCreate();
elp->type = type;
elp->groupPos = groupPos;
elp->childPos = childPos;
elp->flatListPos = flatListPos;
return elp;
}
ExpandableListPosition* ExpandableListPosition::getRecycledOrCreate() {
ExpandableListPosition* elp;
if (sPool.size() > 0) {
elp = sPool.front();
sPool.pop();
} else {
return new ExpandableListPosition();
}
elp->resetState();
return elp;
}
/**
* Do not call this unless you obtained this via ExpandableListPosition.obtain().
* PositionMetadata will handle recycling its own children.
*/
void ExpandableListPosition::recycle()const{
if (sPool.size() < MAX_POOL_SIZE) {
sPool.push((ExpandableListPosition*)this);
}
}
}

View File

@ -1,44 +0,0 @@
#ifndef __EXPANDABLE_LIST_POSITION_H__
#define __EXPANDABLE_LIST_POSITION_H__
#include <queue>
namespace cdroid{
class ExpandableListPosition {
private:
static constexpr int MAX_POOL_SIZE = 5;
static std::queue<ExpandableListPosition*> sPool;
private:
void resetState();
ExpandableListPosition();
static ExpandableListPosition* getRecycledOrCreate();
public:
/* This data type represents a child position */
static constexpr int CHILD = 1;
/* This data type represents a group position */
static constexpr int GROUP = 2;
/* The position of either the group being referred to, or the parent
* group of the child being referred to */
int groupPos;
/* The position of the child within its parent group */
int childPos;
/* The position of the item in the flat list (optional, used internally when
* the corresponding flat list position for the group or child is known) */
int flatListPos;
/* What type of position this ExpandableListPosition represents */
int type;
public:
long getPackedPosition();
static ExpandableListPosition* obtainGroupPosition(int groupPosition);
static ExpandableListPosition* obtainChildPosition(int groupPosition, int childPosition);
static ExpandableListPosition* obtainPosition(long packedPosition);
static ExpandableListPosition* obtain(int type, int groupPos, int childPos, int flatListPos);
void recycle()const;
};
}/*endof namespace*/
#endif/*__EXPANDABLE_LIST_POSITION_H__*/

View File

@ -1,614 +0,0 @@
#include <widget/expandablelistview.h>
namespace cdroid{
DECLARE_WIDGET(ExpandableListView)
ExpandableListView::ExpandableListView(int w,int h):ListView(w,h){
initView();
}
ExpandableListView::ExpandableListView(Context* context,const AttributeSet& attrs)
:ListView(context,attrs){
initView();
mGroupIndicator = attrs.getDrawable("groupIndicator");
mChildIndicator = attrs.getDrawable("childIndicator");
mIndicatorLeft = attrs.getDimensionPixelSize("indicatorLeft", 0);
mIndicatorRight = attrs.getDimensionPixelSize("indicatorRight", 0);
if (mIndicatorRight == 0 && mGroupIndicator ) {
mIndicatorRight = mIndicatorLeft + mGroupIndicator->getIntrinsicWidth();
}
mChildIndicatorLeft = attrs.getDimensionPixelSize("childIndicatorLeft", CHILD_INDICATOR_INHERIT);
mChildIndicatorRight = attrs.getDimensionPixelSize("childIndicatorRight", CHILD_INDICATOR_INHERIT);
mChildDivider = attrs.getDrawable("childDivider");
if (!isRtlCompatibilityMode()) {
mIndicatorStart = attrs.getDimensionPixelSize("indicatorStart", INDICATOR_UNDEFINED);
mIndicatorEnd = attrs.getDimensionPixelSize("indicatorEnd",INDICATOR_UNDEFINED);
mChildIndicatorStart = attrs.getDimensionPixelSize("childIndicatorStart", CHILD_INDICATOR_INHERIT);
mChildIndicatorEnd = attrs.getDimensionPixelSize("childIndicatorEnd", CHILD_INDICATOR_INHERIT);
}
}
ExpandableListView::~ExpandableListView(){
delete mConnector;
delete mGroupIndicator;
delete mChildIndicator;
delete mChildDivider;
}
void ExpandableListView::initView(){
mGroupIndicator = nullptr;
mChildIndicator = nullptr;
mChildDivider = nullptr;
mIndicatorLeft = 0;
mIndicatorRight= 0;
mConnector = nullptr;
mAdapter = nullptr;
mChildIndicatorLeft = CHILD_INDICATOR_INHERIT;
mChildIndicatorRight= CHILD_INDICATOR_INHERIT;
mIndicatorStart = INDICATOR_UNDEFINED;
mIndicatorEnd = INDICATOR_UNDEFINED;
mChildIndicatorStart = CHILD_INDICATOR_INHERIT;
mChildIndicatorEnd = CHILD_INDICATOR_INHERIT;
}
bool ExpandableListView::isRtlCompatibilityMode()const{
//final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
return /*targetSdkVersion < JELLY_BEAN_MR1 ||*/ !hasRtlSupport();
}
void ExpandableListView::onRtlPropertiesChanged(int layoutDirection){
resolveIndicator();
resolveChildIndicator();
}
void ExpandableListView::resolveIndicator() {
const bool bIsLayoutRtl = isLayoutRtl();
if (bIsLayoutRtl) {
if (mIndicatorStart >= 0) {
mIndicatorRight = mIndicatorStart;
}
if (mIndicatorEnd >= 0) {
mIndicatorLeft = mIndicatorEnd;
}
} else {
if (mIndicatorStart >= 0) {
mIndicatorLeft = mIndicatorStart;
}
if (mIndicatorEnd >= 0) {
mIndicatorRight = mIndicatorEnd;
}
}
if (mIndicatorRight == 0 && mGroupIndicator) {
mIndicatorRight = mIndicatorLeft + mGroupIndicator->getIntrinsicWidth();
}
}
void ExpandableListView::resolveChildIndicator() {
const bool bIsLayoutRtl = isLayoutRtl();
if (bIsLayoutRtl) {
if (mChildIndicatorStart >= CHILD_INDICATOR_INHERIT) {
mChildIndicatorRight = mChildIndicatorStart;
}
if (mChildIndicatorEnd >= CHILD_INDICATOR_INHERIT) {
mChildIndicatorLeft = mChildIndicatorEnd;
}
} else {
if (mChildIndicatorStart >= CHILD_INDICATOR_INHERIT) {
mChildIndicatorLeft = mChildIndicatorStart;
}
if (mChildIndicatorEnd >= CHILD_INDICATOR_INHERIT) {
mChildIndicatorRight = mChildIndicatorEnd;
}
}
}
void ExpandableListView::dispatchDraw(Canvas& canvas) {
// Draw children, etc.
ListView::dispatchDraw(canvas);
// If we have any indicators to draw, we do it here
if ((mChildIndicator == nullptr) && (mGroupIndicator == nullptr)) {
return;
}
const bool clipToPadding = (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
if (clipToPadding) {
canvas.save();
canvas.rectangle(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
mScrollX + mRight - mLeft - mPaddingRight,
mScrollY + mBottom - mTop - mPaddingBottom);
canvas.clip();
}
int headerViewsCount = getHeaderViewsCount();
int lastChildFlPos = mItemCount - getFooterViewsCount() - headerViewsCount - 1;
int myB = mBottom;
ExpandableListConnector::PositionMetadata* pos;
View* item;
Drawable* indicator;
int t, b;
// Start at a value that is neither child nor group
int lastItemType = ~(ExpandableListPosition::CHILD | ExpandableListPosition::GROUP);
Rect indicatorRect;// = mIndicatorRect;
// The "child" mentioned in the following two lines is this
// View's child, not referring to an expandable list's
// notion of a child (as opposed to a group)
const int childCount = getChildCount();
for (int i = 0, childFlPos = mFirstPosition - headerViewsCount; i < childCount;
i++, childFlPos++) {
if (childFlPos < 0) {
// This child is header
continue;
} else if (childFlPos > lastChildFlPos) {
// This child is footer, so are all subsequent children
break;
}
item = getChildAt(i);
t = item->getTop();
b = item->getBottom();
// This item isn't on the screen
if ((b < 0) || (t > myB)) continue;
// Get more expandable list-related info for this item
pos = mConnector->getUnflattenedPos(childFlPos);
const bool bIsLayoutRtl = isLayoutRtl();
const int width = getWidth();
// If this item type and the previous item type are different, then we need to change
// the left & right bounds
if (pos->position->type != lastItemType) {
if (pos->position->type == ExpandableListPosition::CHILD) {
indicatorRect.left = (mChildIndicatorLeft == CHILD_INDICATOR_INHERIT) ?
mIndicatorLeft : mChildIndicatorLeft;
indicatorRect.width = ((mChildIndicatorRight == CHILD_INDICATOR_INHERIT) ?
mIndicatorRight : mChildIndicatorRight) - indicatorRect.left;
} else {
indicatorRect.left = mIndicatorLeft;
indicatorRect.width = mIndicatorRight - mIndicatorLeft;
}
if (bIsLayoutRtl) {
const int temp = indicatorRect.left;
indicatorRect.left = width - indicatorRect.right();
indicatorRect.width = indicatorRect.right() - temp;
indicatorRect.left -= mPaddingRight;
//indicatorRect.right -= mPaddingRight;
} else {
indicatorRect.left += mPaddingLeft;
//indicatorRect.right += mPaddingLeft;
}
lastItemType = pos->position->type;
}
if (indicatorRect.width > 0) {
// Use item's full height + the divider height
if (mStackFromBottom) {
// See ListView#dispatchDraw
indicatorRect.top = t;// - mDividerHeight;
indicatorRect.height = b - t;
} else {
indicatorRect.top = t;
indicatorRect.height = b - t;// + mDividerHeight;
}
// Get the indicator (with its state set to the item's state)
indicator = getIndicator(*pos);
if (indicator) {
// Draw the indicator
indicator->setBounds(indicatorRect);
indicator->draw(canvas);
}
}
pos->recycle();
}
if (clipToPadding) {
canvas.restore();
}
}
Drawable* ExpandableListView::getIndicator(ExpandableListConnector::PositionMetadata& pos) {
Drawable* indicator;
if (pos.position->type == ExpandableListPosition::GROUP) {
indicator = mGroupIndicator;
if (indicator && indicator->isStateful()) {
// Empty check based on availability of data. If the groupMetadata isn't null,
// we do a check on it. Otherwise, the group is collapsed so we consider it
// empty for performance reasons.
const bool isEmpty = (pos.groupMetadata == nullptr) ||
(pos.groupMetadata->lastChildFlPos == pos.groupMetadata->flPos);
const int stateSetIndex = (pos.isExpanded() ? 1 : 0) | // Expanded?
(isEmpty ? 2 : 0); // Empty?
//indicator->setState(GROUP_STATE_SETS[stateSetIndex]);
}
} else {
indicator = mChildIndicator;
if (indicator && indicator->isStateful()) {
// No need for a state sets array for the child since it only has two states
/*int stateSet[] = pos.position.flatListPos == pos.groupMetadata.lastChildFlPos
? CHILD_LAST_STATE_SET : EMPTY_STATE_SET;
indicator->setState(stateSet);*/
}
}
return indicator;
}
void ExpandableListView::setChildDivider(Drawable* childDivider) {
mChildDivider = childDivider;
}
void ExpandableListView::drawDivider(Canvas& canvas, Rect bounds, int childIndex) {
int flatListPosition = childIndex + mFirstPosition;
// Only proceed as possible child if the divider isn't above all items (if it is above
// all items, then the item below it has to be a group)
if (flatListPosition >= 0) {
const int adjustedPosition = getFlatPositionForConnector(flatListPosition);
ExpandableListConnector::PositionMetadata* pos = mConnector->getUnflattenedPos(adjustedPosition);
// If this item is a child, or it is a non-empty group that is expanded
if ((pos->position->type == ExpandableListPosition::CHILD) || (pos->isExpanded() &&
pos->groupMetadata->lastChildFlPos != pos->groupMetadata->flPos)) {
// These are the cases where we draw the child divider
Drawable* divider = mChildDivider;
divider->setBounds(bounds);
divider->draw(canvas);
pos->recycle();
return;
}
pos->recycle();
}
// Otherwise draw the default divider
ListView::drawDivider(canvas, bounds, flatListPosition);
}
/*void ExpandableListView::setOnItemClickListener(OnItemClickListener l) {
ListView::setOnItemClickListener(l);
}*/
void ExpandableListView::setAdapter(ExpandableListAdapter* adapter){
mAdapter = adapter;
if (adapter != nullptr) {
// Create the connector
mConnector = new ExpandableListConnector(adapter);
} else {
mConnector = nullptr;
}
// Link the ListView (superclass) to the expandable list data through the connector
ListView::setAdapter(mConnector);
}
ExpandableListAdapter* ExpandableListView::getExpandableListAdapter(){
return mAdapter;
}
void ExpandableListView::setAdapter(ListAdapter* adapter) {
FATAL("For ExpandableListView, use setAdapter(ExpandableListAdapter) instead of setAdapter(ListAdapter)");
}
bool ExpandableListView::isHeaderOrFooterPosition(int position) {
const int footerViewsStart = mItemCount - getFooterViewsCount();
return (position < getHeaderViewsCount() || position >= footerViewsStart);
}
int ExpandableListView::getFlatPositionForConnector(int flatListPosition) {
return flatListPosition - getHeaderViewsCount();
}
int ExpandableListView::getAbsoluteFlatPosition(int flatListPosition) {
return flatListPosition + getHeaderViewsCount();
}
bool ExpandableListView::performItemClick(View& v, int position, long id) {
// Ignore clicks in header/footers
if (isHeaderOrFooterPosition(position)) {
// Clicked on a header/footer, so ignore pass it on to super
return ListView::performItemClick(v, position, id);
}
// Internally handle the item click
const int adjustedPosition = getFlatPositionForConnector(position);
return handleItemClick(v, adjustedPosition, id);
}
bool ExpandableListView::handleItemClick(View& v, int position, long id) {
ExpandableListConnector::PositionMetadata* posMetadata = mConnector->getUnflattenedPos(position);
id = getChildOrGroupId(*posMetadata->position);
bool returnValue;
if (posMetadata->position->type == ExpandableListPosition::GROUP) {
/* It's a group, so handle collapsing/expanding */
/* It's a group click, so pass on event */
if (mOnGroupClickListener) {
if (mOnGroupClickListener(*this, v, posMetadata->position->groupPos, id)) {
posMetadata->recycle();
return true;
}
}
if (posMetadata->isExpanded()) {
/* Collapse it */
mConnector->collapseGroup(*posMetadata);
playSoundEffect(SoundEffectConstants::CLICK);
if (mOnGroupCollapseListener) {
mOnGroupCollapseListener(posMetadata->position->groupPos);
}
} else {
/* Expand it */
mConnector->expandGroup(*posMetadata);
playSoundEffect(SoundEffectConstants::CLICK);
if (mOnGroupExpandListener) {
mOnGroupExpandListener(posMetadata->position->groupPos);
}
const int groupPos = posMetadata->position->groupPos;
const int groupFlatPos = posMetadata->position->flatListPos;
const int shiftedGroupPosition = groupFlatPos + getHeaderViewsCount();
smoothScrollToPosition(shiftedGroupPosition + mAdapter->getChildrenCount(groupPos),
shiftedGroupPosition);
}
returnValue = true;
} else {
/* It's a child, so pass on event */
if (mOnChildClickListener) {
playSoundEffect(SoundEffectConstants::CLICK);
return mOnChildClickListener(*this, v, posMetadata->position->groupPos,
posMetadata->position->childPos, id);
}
returnValue = false;
}
posMetadata->recycle();
return returnValue;
}
bool ExpandableListView::expandGroup(int groupPos) {
return expandGroup(groupPos, false);
}
bool ExpandableListView::expandGroup(int groupPos, bool animate) {
ExpandableListPosition* elGroupPos = ExpandableListPosition::obtain(
ExpandableListPosition::GROUP, groupPos, -1, -1);
ExpandableListConnector::PositionMetadata* pm = mConnector->getFlattenedPos(*elGroupPos);
elGroupPos->recycle();
const bool retValue = mConnector->expandGroup(*pm);
if (mOnGroupExpandListener) {
mOnGroupExpandListener(groupPos);
}
if (animate) {
const int groupFlatPos = pm->position->flatListPos;
const int shiftedGroupPosition = groupFlatPos + getHeaderViewsCount();
smoothScrollToPosition(shiftedGroupPosition + mAdapter->getChildrenCount(groupPos),
shiftedGroupPosition);
}
pm->recycle();
return retValue;
}
bool ExpandableListView::collapseGroup(int groupPos) {
const bool retValue = mConnector->collapseGroup(groupPos);
if (mOnGroupCollapseListener ) {
mOnGroupCollapseListener(groupPos);
}
return retValue;
}
void ExpandableListView::setOnGroupCollapseListener(OnGroupCollapseListener onGroupCollapseListener){
mOnGroupCollapseListener = onGroupCollapseListener;
}
void ExpandableListView::setOnGroupExpandListener( OnGroupExpandListener onGroupExpandListener) {
mOnGroupExpandListener = onGroupExpandListener;
}
void ExpandableListView::setOnGroupClickListener(OnGroupClickListener onGroupClickListener) {
mOnGroupClickListener = onGroupClickListener;
}
void ExpandableListView::setOnChildClickListener(OnChildClickListener onChildClickListener) {
mOnChildClickListener = onChildClickListener;
}
long ExpandableListView::getExpandableListPosition(int flatListPosition) {
if (isHeaderOrFooterPosition(flatListPosition)) {
return PACKED_POSITION_VALUE_NULL;
}
const int adjustedPosition = getFlatPositionForConnector(flatListPosition);
ExpandableListConnector::PositionMetadata* pm = mConnector->getUnflattenedPos(adjustedPosition);
const long packedPos = pm->position->getPackedPosition();
pm->recycle();
return packedPos;
}
int ExpandableListView::getFlatListPosition(long packedPosition) {
ExpandableListPosition* elPackedPos = ExpandableListPosition::obtainPosition(packedPosition);
ExpandableListConnector::PositionMetadata* pm = mConnector->getFlattenedPos(*elPackedPos);
elPackedPos->recycle();
const int flatListPosition = pm->position->flatListPos;
pm->recycle();
return getAbsoluteFlatPosition(flatListPosition);
}
long ExpandableListView::getSelectedPosition() {
const int selectedPos = getSelectedItemPosition();
// The case where there is no selection (selectedPos == -1) is also handled here.
return getExpandableListPosition(selectedPos);
}
long ExpandableListView::getSelectedId() {
long packedPos = getSelectedPosition();
if (packedPos == PACKED_POSITION_VALUE_NULL) return -1;
int groupPos = getPackedPositionGroup(packedPos);
if (getPackedPositionType(packedPos) == PACKED_POSITION_TYPE_GROUP) {
// It's a group
return mAdapter->getGroupId(groupPos);
} else {
// It's a child
return mAdapter->getChildId(groupPos, getPackedPositionChild(packedPos));
}
}
void ExpandableListView::setSelectedGroup(int groupPosition) {
ExpandableListPosition* elGroupPos = ExpandableListPosition::obtainGroupPosition(groupPosition);
ExpandableListConnector::PositionMetadata* pm = mConnector->getFlattenedPos(*elGroupPos);
elGroupPos->recycle();
const int absoluteFlatPosition = getAbsoluteFlatPosition(pm->position->flatListPos);
ListView::setSelection(absoluteFlatPosition);
pm->recycle();
}
bool ExpandableListView::setSelectedChild(int groupPosition, int childPosition, bool shouldExpandGroup) {
ExpandableListPosition* elChildPos = ExpandableListPosition::obtainChildPosition(groupPosition, childPosition);
ExpandableListConnector::PositionMetadata* flatChildPos = mConnector->getFlattenedPos(*elChildPos);
if (flatChildPos == nullptr) {
// The child's group isn't expanded
// Shouldn't expand the group, so return false for we didn't set the selection
if (!shouldExpandGroup) return false;
expandGroup(groupPosition);
flatChildPos = mConnector->getFlattenedPos(*elChildPos);
// Validity check
if (flatChildPos == nullptr) {
FATAL("Could not find child");
}
}
const int absoluteFlatPosition = getAbsoluteFlatPosition(flatChildPos->position->flatListPos);
ListView::setSelection(absoluteFlatPosition);
elChildPos->recycle();
flatChildPos->recycle();
return true;
}
bool ExpandableListView::isGroupExpanded(int groupPosition) {
return mConnector->isGroupExpanded(groupPosition);
}
int ExpandableListView::getPackedPositionType(long packedPosition) {
if (packedPosition == PACKED_POSITION_VALUE_NULL) {
return PACKED_POSITION_TYPE_NULL;
}
return (packedPosition & PACKED_POSITION_MASK_TYPE) == PACKED_POSITION_MASK_TYPE
? PACKED_POSITION_TYPE_CHILD : PACKED_POSITION_TYPE_GROUP;
}
int ExpandableListView::getPackedPositionGroup(long packedPosition) {
// Null
if (packedPosition == PACKED_POSITION_VALUE_NULL) return -1;
return (int) ((packedPosition & PACKED_POSITION_MASK_GROUP) >> PACKED_POSITION_SHIFT_GROUP);
}
int ExpandableListView::getPackedPositionChild(long packedPosition) {
// Null
if (packedPosition == PACKED_POSITION_VALUE_NULL) return -1;
// Group since a group type clears this bit
if ((packedPosition & PACKED_POSITION_MASK_TYPE) != PACKED_POSITION_MASK_TYPE) return -1;
return (int) (packedPosition & PACKED_POSITION_MASK_CHILD);
}
long ExpandableListView::getPackedPositionForChild(int groupPosition, int childPosition) {
return (((int64_t)PACKED_POSITION_TYPE_CHILD) << PACKED_POSITION_SHIFT_TYPE)
| ((((int64_t)groupPosition) & PACKED_POSITION_INT_MASK_GROUP)
<< PACKED_POSITION_SHIFT_GROUP)
| (childPosition & PACKED_POSITION_INT_MASK_CHILD);
}
long ExpandableListView::getPackedPositionForGroup(int groupPosition) {
// No need to OR a type in because PACKED_POSITION_GROUP == 0
return ((((int64_t)groupPosition) & PACKED_POSITION_INT_MASK_GROUP)
<< PACKED_POSITION_SHIFT_GROUP);
}
long ExpandableListView::getChildOrGroupId(const ExpandableListPosition& position) {
if (position.type == ExpandableListPosition::CHILD) {
return mAdapter->getChildId(position.groupPos, position.childPos);
} else {
return mAdapter->getGroupId(position.groupPos);
}
}
void ExpandableListView::setChildIndicator(Drawable* childIndicator) {
mChildIndicator = childIndicator;
}
void ExpandableListView::setChildIndicatorBounds(int left, int right) {
mChildIndicatorLeft = left;
mChildIndicatorRight = right;
resolveChildIndicator();
}
void ExpandableListView::setChildIndicatorBoundsRelative(int start, int end) {
mChildIndicatorStart = start;
mChildIndicatorEnd = end;
resolveChildIndicator();
}
void ExpandableListView::setGroupIndicator(Drawable* groupIndicator) {
mGroupIndicator = groupIndicator;
if (mIndicatorRight == 0 && mGroupIndicator ) {
mIndicatorRight = mIndicatorLeft + mGroupIndicator->getIntrinsicWidth();
}
}
void ExpandableListView::setIndicatorBounds(int left, int right) {
mIndicatorLeft = left;
mIndicatorRight = right;
resolveIndicator();
}
void ExpandableListView::setIndicatorBoundsRelative(int start, int end) {
mIndicatorStart = start;
mIndicatorEnd = end;
resolveIndicator();
}
}/*endof namespace*/

View File

@ -1,148 +0,0 @@
#ifndef __EXPANDABLE_LISTVIEW_H__
#define __EXPANDABLE_LISTVIEW_H__
#include <widget/listview.h>
#include <widget/expandablelistconnector.h>
#include <widget/expandablelistposition.h>
#include <widget/baseexpandablelistadapter.h>
namespace cdroid{
class ExpandableListView:public ListView{
private:
static constexpr int64_t PACKED_POSITION_MASK_CHILD = 0x00000000FFFFFFFFL;
/** The mask (in packed position representation) for the group */
static constexpr int64_t PACKED_POSITION_MASK_GROUP = 0x7FFFFFFF00000000L;
/** The mask (in packed position representation) for the type */
static constexpr int64_t PACKED_POSITION_MASK_TYPE = 0x8000000000000000L;
/** The shift amount (in packed position representation) for the group */
static constexpr long PACKED_POSITION_SHIFT_GROUP = 32;
/** The shift amount (in packed position representation) for the type */
static constexpr long PACKED_POSITION_SHIFT_TYPE = 63;
/** The mask (in integer child position representation) for the child */
static constexpr long PACKED_POSITION_INT_MASK_CHILD = 0xFFFFFFFF;
/** The mask (in integer group position representation) for the group */
static constexpr long PACKED_POSITION_INT_MASK_GROUP = 0x7FFFFFFF;
/* Denotes an undefined value for an indicator */
static constexpr int INDICATOR_UNDEFINED = -2;
public:
/* The packed position represents a group. */
static constexpr int PACKED_POSITION_TYPE_GROUP = 0;
/* The packed position represents a child. */
static constexpr int PACKED_POSITION_TYPE_CHILD = 1;
/* The packed position represents a neither/null/no preference. */
static constexpr int PACKED_POSITION_TYPE_NULL = 2;
/* The value for a packed position that represents neither/null/no
* preference. This value is not otherwise possible since a group type
* (first bit 0) should not have a child position filled. */
static constexpr long PACKED_POSITION_VALUE_NULL = 0x00000000FFFFFFFFL;
/* Denotes when a child indicator should inherit this bound from the generic
* indicator bounds */
static constexpr int CHILD_INDICATOR_INHERIT = -1;
DECLARE_UIEVENT(void,OnGroupExpandListener,int);
DECLARE_UIEVENT(void,OnGroupCollapseListener,int);
DECLARE_UIEVENT(bool,OnGroupClickListener,ExpandableListView& parent, View& v, int groupPosition, long id);
DECLARE_UIEVENT(bool,OnChildClickListener,ExpandableListView& parent, View& v, int groupPosition, int childPosition, long id);
private:
int mIndicatorLeft;
/** Right bound for drawing the indicator. */
int mIndicatorRight;
/** Start bound for drawing the indicator. */
int mIndicatorStart;
/** End bound for drawing the indicator. */
int mIndicatorEnd;
/* Left bound for drawing the indicator of a child. Value of
* {@link #CHILD_INDICATOR_INHERIT} means use mIndicatorLeft.*/
int mChildIndicatorLeft;
/* Right bound for drawing the indicator of a child. Value of
* {@link #CHILD_INDICATOR_INHERIT} means use mIndicatorRight. */
int mChildIndicatorRight;
/* Start bound for drawing the indicator of a child. Value of
* {@link #CHILD_INDICATOR_INHERIT} means use mIndicatorStart.*/
int mChildIndicatorStart;
/* End bound for drawing the indicator of a child. Value of
* {@link #CHILD_INDICATOR_INHERIT} means use mIndicatorEnd. */
int mChildIndicatorEnd;
ExpandableListConnector* mConnector;
ExpandableListAdapter* mAdapter;
/** The indicator drawn next to a group. */
Drawable* mGroupIndicator;
/** The indicator drawn next to a child. */
Drawable* mChildIndicator;
/** Drawable to be used as a divider when it is adjacent to any children */
Drawable* mChildDivider;
OnGroupExpandListener mOnGroupExpandListener;
OnGroupCollapseListener mOnGroupCollapseListener;
OnGroupClickListener mOnGroupClickListener;
OnChildClickListener mOnChildClickListener;
private:
void initView();
bool isRtlCompatibilityMode()const;
void resolveIndicator();
void resolveChildIndicator();
Drawable* getIndicator(ExpandableListConnector::PositionMetadata& pos);
bool isHeaderOrFooterPosition(int position);
int getFlatPositionForConnector(int flatListPosition);
int getAbsoluteFlatPosition(int flatListPosition);
long getChildOrGroupId(const ExpandableListPosition& position);
protected:
void dispatchDraw(Canvas& canvas);
void drawDivider(Canvas& canvas, Rect bounds, int childIndex);
bool handleItemClick(View& v, int position, long id);
public:
ExpandableListView(int,int);
ExpandableListView(Context* context,const AttributeSet& attrs);
~ExpandableListView();
void setAdapter(ListAdapter* adapter);
void setAdapter(ExpandableListAdapter* adapter);
ExpandableListAdapter* getExpandableListAdapter();
void onRtlPropertiesChanged(int layoutDirection);
void setChildDivider(Drawable* childDivider);
bool performItemClick(View& v, int position, long id)override;
bool expandGroup(int groupPos);
bool expandGroup(int groupPos, bool animate);
bool collapseGroup(int groupPos);
void setOnGroupCollapseListener(OnGroupCollapseListener onGroupCollapseListener);
void setOnGroupExpandListener( OnGroupExpandListener onGroupExpandListener);
void setOnGroupClickListener(OnGroupClickListener onGroupClickListener);
void setOnChildClickListener(OnChildClickListener onChildClickListener);
long getExpandableListPosition(int flatListPosition);
int getFlatListPosition(long packedPosition);
long getSelectedPosition();
long getSelectedId();
void setSelectedGroup(int groupPosition);
bool setSelectedChild(int groupPosition, int childPosition, bool shouldExpandGroup);
bool isGroupExpanded(int groupPosition);
static int getPackedPositionType(long packedPosition);
static int getPackedPositionGroup(long packedPosition);
static int getPackedPositionChild(long packedPosition);
static long getPackedPositionForChild(int groupPosition, int childPosition);
static long getPackedPositionForGroup(int groupPosition);
void setChildIndicator(Drawable* childIndicator);
void setChildIndicatorBounds(int left, int right);
void setChildIndicatorBoundsRelative(int start, int end);
void setGroupIndicator(Drawable* groupIndicator);
void setIndicatorBounds(int left, int right);
void setIndicatorBoundsRelative(int start, int end);
};
}/*endof namespace*/
#endif