mirror of
https://gitee.com/houstudio/Cdroid.git
synced 2024-11-30 03:08:12 +08:00
fix AdapterHelper's OpReorderer
This commit is contained in:
parent
6ab9e07fd5
commit
bfe3889e49
@ -36,6 +36,7 @@ public:
|
||||
TextView*textView = ((MyAdapter::ViewHolder&)holder).textView;
|
||||
textView->setText(item);
|
||||
textView->setId(position);
|
||||
LOGD("%p:%d",textView,position);
|
||||
textView->setOnClickListener([position](View&v){
|
||||
RecyclerView*rv = (RecyclerView*)v.getParent();
|
||||
RecyclerView::LayoutManager*mgr = rv->getLayoutManager();
|
||||
@ -88,6 +89,7 @@ int main(int argc,const char*argv[]){
|
||||
r=[&](){
|
||||
adapter->remove(4);
|
||||
adapter->notifyItemRemoved(4);
|
||||
w->postDelayed(r,3000);
|
||||
};
|
||||
w->postDelayed(r,8000);
|
||||
app.exec();
|
||||
|
@ -32,12 +32,12 @@ Keyboard::Key::Key(void*parent,int x,int y,Context*context,const AttributeSet&at
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
Keyboard::Row*row=(Keyboard::Row*)parent;
|
||||
Keyboard*keyboard =row->parent;
|
||||
Keyboard*keyboard = row->parent;
|
||||
width = getDimensionOrFraction(attrs,"keyWidth" , keyboard->mDisplayWidth, row->defaultWidth );
|
||||
height= getDimensionOrFraction(attrs,"keyHeight", keyboard->mDisplayHeight, row->defaultHeight);
|
||||
gap = getDimensionOrFraction(attrs,"horizontalGap", keyboard->mDisplayWidth, row->defaultHorizontalGap);
|
||||
edgeFlags =row->rowEdgeFlags | attrs.getInt("keyEdgeFlags",edgeFlagKVS,0);
|
||||
this->x+=gap;
|
||||
this->x += gap;
|
||||
const std::string resicon=attrs.getString("keyIcon");
|
||||
icon = resicon.empty()?nullptr:context->getDrawable(resicon);
|
||||
label = attrs.getString("keyLabel");
|
||||
@ -50,18 +50,19 @@ Keyboard::Key::Key(void*parent,int x,int y,Context*context,const AttributeSet&at
|
||||
std::wstring ws=TextUtils::utf8tounicode(label);
|
||||
codes.push_back(ws[0]);
|
||||
}
|
||||
LOGV("Key[%x]%s(%d,%d,%d,%d) gap=%d",codes[0],label.c_str(),x,y,width,height,gap);
|
||||
}
|
||||
|
||||
Keyboard::Key::Key(void*p){
|
||||
parent =p;
|
||||
Row*row=(Row*)parent;
|
||||
sticky =modifier=0;
|
||||
parent = p;
|
||||
Row*row= (Row*)parent;
|
||||
sticky = modifier = 0;
|
||||
x= y = gap =0;
|
||||
width = row->defaultWidth;
|
||||
height = row->defaultHeight;
|
||||
edgeFlags= row->rowEdgeFlags;
|
||||
width = row->defaultWidth;
|
||||
height = row->defaultHeight;
|
||||
edgeFlags = row->rowEdgeFlags;
|
||||
on = false;
|
||||
pressed=false;
|
||||
pressed = false;
|
||||
}
|
||||
|
||||
void Keyboard::Key::onPressed() {
|
||||
@ -90,10 +91,10 @@ int Keyboard::Key::parseCSV(const std::string& value,std::vector<int>& codes){
|
||||
}
|
||||
|
||||
bool Keyboard::Key::isInside(int x, int y) {
|
||||
bool leftEdge = (edgeFlags & EDGE_LEFT) > 0;
|
||||
bool rightEdge = (edgeFlags & EDGE_RIGHT) > 0;
|
||||
bool topEdge = (edgeFlags & EDGE_TOP) > 0;
|
||||
bool bottomEdge = (edgeFlags & EDGE_BOTTOM) > 0;
|
||||
const bool leftEdge = (edgeFlags & EDGE_LEFT) > 0;
|
||||
const bool rightEdge = (edgeFlags & EDGE_RIGHT) > 0;
|
||||
const bool topEdge = (edgeFlags & EDGE_TOP) > 0;
|
||||
const bool bottomEdge = (edgeFlags & EDGE_BOTTOM) > 0;
|
||||
if ((x >= this->x || (leftEdge && x <= this->x + this->width))
|
||||
&& (x < this->x + this->width || (rightEdge && x >= this->x))
|
||||
&& (y >= this->y || (topEdge && y <= this->y + this->height))
|
||||
@ -105,8 +106,8 @@ bool Keyboard::Key::isInside(int x, int y) {
|
||||
}
|
||||
|
||||
int Keyboard::Key::squaredDistanceFrom(int x, int y){
|
||||
int xDist = this->x + width / 2 - x;
|
||||
int yDist = this->y + height / 2 - y;
|
||||
const int xDist = this->x + width / 2 - x;
|
||||
const int yDist = this->y + height / 2 - y;
|
||||
return xDist * xDist + yDist * yDist;
|
||||
}
|
||||
|
||||
@ -255,7 +256,7 @@ static void endTag(void *userData, const XML_Char *name){
|
||||
keyboard->getModifierKeys().push_back(key);
|
||||
}
|
||||
}else if(0==strcmp(name,"Row")){
|
||||
pd->y += row->defaultHeight+row->verticalGap;
|
||||
pd->y += (row->defaultHeight + row->verticalGap);
|
||||
pd->minWidth = std::max(pd->x,pd->minWidth);
|
||||
pd->x = 0;
|
||||
if(row->mode == pd->keyboardMode)
|
||||
@ -293,11 +294,11 @@ void Keyboard::loadKeyboard(Context*context,const std::string&resid){
|
||||
} while(len!=0);
|
||||
}
|
||||
XML_ParserFree(parser);
|
||||
mTotalHeight= pd.y-mDefaultVerticalGap;
|
||||
mTotalHeight= pd.y - mDefaultVerticalGap;
|
||||
mTotalWidth = pd.minWidth;
|
||||
mProximityThreshold = mDefaultWidth*.6f;//SEARCH_DISTANCE;
|
||||
mProximityThreshold*= mProximityThreshold;
|
||||
LOGD("%s endof loadkeyboard %d rows %d keys gaps=%d,%d parsed size=%dx%d display=%dx%d",
|
||||
LOGD("%s endof loadkeyboard %d rows %d keys gaps=%d,%d parsed.Size=%dx%d display=%dx%d",
|
||||
resid.c_str(),rows.size(),mKeys.size(), getHorizontalGap(),getVerticalGap(),
|
||||
mTotalWidth,mTotalHeight,mDisplayWidth,mDisplayHeight);
|
||||
}
|
||||
@ -435,7 +436,7 @@ void Keyboard::computeNearestNeighbors() {
|
||||
std::vector<int> Keyboard::getNearestKeys(int x, int y){
|
||||
if (mGridNeighbors.size() ==0) computeNearestNeighbors();
|
||||
if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) {
|
||||
int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth);
|
||||
const int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth);
|
||||
if (index < GRID_SIZE) {
|
||||
return mGridNeighbors[index];
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
namespace cdroid{
|
||||
|
||||
@ -680,13 +681,13 @@ void KeyboardView::SwipeTracker::addPoint(float x,float y,long time){
|
||||
}
|
||||
|
||||
void KeyboardView::SwipeTracker::computeCurrentVelocity(int units){
|
||||
//computeCurrentVelocity(units,FLT_MAX);
|
||||
computeCurrentVelocity(units,FLT_MAX);
|
||||
}
|
||||
|
||||
void KeyboardView::SwipeTracker::computeCurrentVelocity(int units,float maxVelocity){
|
||||
float oldestX = mPastX[0];//pastX[0];
|
||||
float oldestY = mPastY[0];//pastY[0];
|
||||
long oldestTime = mPastTime[0];//pastTime[0];
|
||||
float oldestX = mPastX[0];
|
||||
float oldestY = mPastY[0];
|
||||
long oldestTime = mPastTime[0];
|
||||
float accumX = 0;
|
||||
float accumY = 0;
|
||||
int N=0;
|
||||
|
@ -9,7 +9,11 @@ AdapterHelper::AdapterHelper(Callback callback)
|
||||
AdapterHelper::AdapterHelper(Callback callback, bool disableRecycler) {
|
||||
mCallback = callback;
|
||||
mDisableRecycler = disableRecycler;
|
||||
mOpReorderer = nullptr;//new OpReorderer(this);
|
||||
OpReorderer::Callback cbk;
|
||||
cbk.obtainUpdateOp = std::bind(&AdapterHelper::obtainUpdateOp,this,std::placeholders::_1,
|
||||
std::placeholders::_2,std::placeholders::_3,std::placeholders::_4);
|
||||
cbk.recycleUpdateOp= std::bind(&AdapterHelper::recycleUpdateOp,this,std::placeholders::_1);
|
||||
mOpReorderer = new OpReorderer(cbk);
|
||||
mUpdateOpPool = new Pools::SimplePool<UpdateOp>(UpdateOp::POOL_SIZE);
|
||||
}
|
||||
|
||||
@ -19,7 +23,6 @@ AdapterHelper::~AdapterHelper(){
|
||||
}
|
||||
|
||||
AdapterHelper& AdapterHelper::addUpdateOp(const std::vector<UpdateOp*>&ops) {
|
||||
//Collections.addAll(mPendingUpdates, ops);
|
||||
mPendingUpdates.insert(mPendingUpdates.end(),ops.begin(),ops.end());
|
||||
return *this;
|
||||
}
|
||||
@ -164,19 +167,19 @@ void AdapterHelper::dispatchAndUpdateViewHolders(UpdateOp* op) {
|
||||
if (op->cmd == UpdateOp::ADD || op->cmd == UpdateOp::MOVE) {
|
||||
throw "should not dispatch add or move for pre layout";
|
||||
}
|
||||
/*if (_DEBUG) {
|
||||
LOGD("dispatch (pre)" + op);
|
||||
Log.d(TAG, "postponed state before:");
|
||||
for (UpdateOp updateOp : mPostponedList) {
|
||||
Log.d(TAG, updateOp.toString());
|
||||
if (_DEBUG) {
|
||||
LOGD("dispatch (pre)%p" ,op);
|
||||
LOGD("postponed state before:");
|
||||
for (UpdateOp* updateOp : mPostponedList) {
|
||||
LOGD("%s",updateOp->toString().c_str());
|
||||
}
|
||||
Log.d(TAG, "----");
|
||||
}*/
|
||||
LOGD("----");
|
||||
}
|
||||
|
||||
// handle each pos 1 by 1 to ensure continuity. If it breaks, dispatch partial
|
||||
// TODO Since move ops are pushed to end, we should not need this anymore
|
||||
int tmpStart = updatePositionWithPostponed(op->positionStart, op->cmd);
|
||||
LOGD_IF(_DEBUG,"pos:%d,updatedPos:%d",op->positionStart,tmpStart);
|
||||
LOGD_IF(_DEBUG,"pos:%d,updatedPos:%d mPostponedList.size=%d",op->positionStart,tmpStart,mPostponedList.size());
|
||||
int tmpCnt = 1;
|
||||
int offsetPositionForPartial = op->positionStart;
|
||||
int positionMultiplier;
|
||||
@ -221,7 +224,7 @@ void AdapterHelper::dispatchAndUpdateViewHolders(UpdateOp* op) {
|
||||
LOGD("post dispatch");
|
||||
LOGD("postponed state after:");
|
||||
for (UpdateOp* updateOp : mPostponedList) {
|
||||
//Log.d(TAG, updateOp.toString());
|
||||
LOGD("%s",updateOp->toString().c_str());
|
||||
}
|
||||
LOGD("----");
|
||||
}
|
||||
@ -297,14 +300,14 @@ int AdapterHelper::updatePositionWithPostponed(int pos, int cmd) {
|
||||
}
|
||||
}
|
||||
}
|
||||
/*if (_DEBUG) {
|
||||
Log.d(TAG, "dispath (step" + i + ")");
|
||||
Log.d(TAG, "postponed state:" + i + ", pos:" + pos);
|
||||
if (_DEBUG) {
|
||||
LOGD("dispath (step %d)",i);
|
||||
LOGD("postponed state:%d, pos:%d",i,pos);
|
||||
for (UpdateOp* updateOp : mPostponedList) {
|
||||
Log.d(TAG, updateOp.toString());
|
||||
LOGD(updateOp->toString().c_str());
|
||||
}
|
||||
Log.d(TAG, "----");
|
||||
}*/
|
||||
LOGD("----");
|
||||
}
|
||||
}
|
||||
for (int i = mPostponedList.size() - 1; i >= 0; i--) {
|
||||
UpdateOp* op = mPostponedList.at(i);
|
||||
@ -346,10 +349,8 @@ void AdapterHelper::applyAdd(UpdateOp* op) {
|
||||
}
|
||||
|
||||
void AdapterHelper::postponeAndUpdateViewHolders(UpdateOp* op) {
|
||||
if (_DEBUG) {
|
||||
LOGD("postponing %d",op->cmd);
|
||||
}
|
||||
mPostponedList.push_back(op);//add(op);
|
||||
LOGD_IF(_DEBUG,"postponing op->%p:%d mPostponedList.size=%d",op,op->cmd,mPostponedList.size());
|
||||
switch (op->cmd) {
|
||||
case UpdateOp::ADD:
|
||||
mCallback.offsetPositionsForAdd(op->positionStart, op->itemCount);
|
||||
@ -560,9 +561,9 @@ void AdapterHelper::recycleUpdateOpsAndClearList(std::vector<UpdateOp*>& ops) {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AdapterHelper::UpdateOp::UpdateOp(){
|
||||
cmd =0;
|
||||
itemCount=0;
|
||||
payload =nullptr;
|
||||
cmd = 0;
|
||||
itemCount = 0;
|
||||
payload = nullptr;
|
||||
}
|
||||
|
||||
AdapterHelper::UpdateOp::UpdateOp(int cmd, int positionStart, int itemCount, Object* payload) {
|
||||
@ -578,4 +579,13 @@ int AdapterHelper::UpdateOp::hashCode() {
|
||||
result = 31 * result + itemCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string AdapterHelper::UpdateOp::toString()const{
|
||||
std::ostringstream oss;
|
||||
const char*cmds[]={"add","rm","up","mv"};
|
||||
const int idx = __builtin_clz(cmd);
|
||||
oss<<cmds[idx]<<",s:"<<positionStart<<" c:"<<itemCount;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
}/*endof namespace*/
|
||||
|
@ -23,6 +23,7 @@ public:
|
||||
UpdateOp();
|
||||
UpdateOp(int cmd, int positionStart, int itemCount, Object* payload);
|
||||
int hashCode();
|
||||
const std::string toString()const;
|
||||
};
|
||||
struct Callback {
|
||||
std::function<RecyclerView::ViewHolder*(int)> findViewHolder;//(int position)
|
||||
|
@ -149,24 +149,43 @@ bool DefaultItemAnimator::animateAdd(RecyclerView::ViewHolder& holder) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void DefaultItemAnimator::onAddAnimationStart(RecyclerView::ViewHolder*holder,Animator& animator,bool isReverse){
|
||||
dispatchAddStarting(*holder);
|
||||
}
|
||||
void DefaultItemAnimator::onAddAnimationCancel(RecyclerView::ViewHolder*holder,Animator& animator,bool isReverse){
|
||||
holder->itemView->setAlpha(1);
|
||||
}
|
||||
void DefaultItemAnimator::onAddAnimationEnd(RecyclerView::ViewHolder*holder,Animator& animator,bool isReverse){
|
||||
View* view = holder->itemView;
|
||||
ViewPropertyAnimator& animation = view->animate();
|
||||
animation.setListener({});
|
||||
dispatchAddFinished(*holder);
|
||||
auto it = std::find(mAddAnimations.begin(), mAddAnimations.end(),holder);
|
||||
mAddAnimations.erase(it);//mAddAnimations.remove(holder);
|
||||
dispatchFinishedWhenDone();
|
||||
}
|
||||
|
||||
void DefaultItemAnimator::animateAddImpl(RecyclerView::ViewHolder& holder) {
|
||||
View* view = holder.itemView;
|
||||
ViewPropertyAnimator& animation = view->animate();
|
||||
mAddAnimations.push_back(&holder);//add(holder);
|
||||
Animator::AnimatorListener al;
|
||||
al.onAnimationStart = [this,&holder](Animator&animator,bool isReverse){
|
||||
al.onAnimationStart = std::bind(&DefaultItemAnimator::onAddAnimationStart,this,&holder,std::placeholders::_1,std::placeholders::_2);
|
||||
/*[this,&holder](Animator&animator,bool isReverse){
|
||||
dispatchAddStarting(holder);
|
||||
};
|
||||
al.onAnimationCancel=[&holder](Animator&){
|
||||
};*/
|
||||
//al.onAnimationCancel= std::bind(&DefaultItemAnimator::onAddAnimationCancel,this,&holder,std::placeholders::_1,std::placeholders::_2);
|
||||
/*[&holder](Animator&){
|
||||
holder.itemView->setAlpha(1);
|
||||
};
|
||||
al.onAnimationEnd = [this,&holder,&animation](Animator& animator,bool isReverse){
|
||||
};*/
|
||||
al.onAnimationEnd = std::bind(&DefaultItemAnimator::onAddAnimationEnd,this,&holder,std::placeholders::_1,std::placeholders::_2);
|
||||
/*[this,&holder,&animation](Animator& animator,bool isReverse){
|
||||
animation.setListener({});
|
||||
dispatchAddFinished(holder);
|
||||
auto it = std::find(mAddAnimations.begin(), mAddAnimations.end(),&holder);
|
||||
mAddAnimations.erase(it);//mAddAnimations.remove(holder);
|
||||
dispatchFinishedWhenDone();
|
||||
};
|
||||
};*/
|
||||
animation.alpha(1).setDuration(getAddDuration()).setListener(al).start();
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,9 @@ protected:
|
||||
int fromX, int fromY, int toX, int toY);
|
||||
};
|
||||
protected:
|
||||
void onAddAnimationStart(RecyclerView::ViewHolder*,Animator& animator,bool isReverse);
|
||||
void onAddAnimationCancel(RecyclerView::ViewHolder*,Animator& animator,bool isReverse);
|
||||
void onAddAnimationEnd(RecyclerView::ViewHolder*,Animator& animator,bool isReverse);
|
||||
void onRemoveAnimationStart(RecyclerView::ViewHolder*,Animator& animator,bool isReverse);
|
||||
void onRemoveAnimationEnd(RecyclerView::ViewHolder*,Animator& animator,bool isReverse);
|
||||
void onMoveAnimationStart(RecyclerView::ViewHolder*,Animator& animator,bool isReverse);
|
||||
|
@ -9,6 +9,7 @@ GridLayoutManager::GridLayoutManager(Context* context,const AttributeSet& attrs)
|
||||
mSpanSizeLookup = new DefaultSpanSizeLookup();
|
||||
setSpanCount(properties->spanCount);
|
||||
delete properties;
|
||||
mPendingSpanCountChange = false;
|
||||
}
|
||||
|
||||
GridLayoutManager::GridLayoutManager(Context* context, int spanCount)
|
||||
|
@ -14,6 +14,7 @@ LinearLayoutManager::LinearLayoutManager(Context* context,int orientation,bool r
|
||||
mLayoutState = nullptr;
|
||||
mOrientationHelper = nullptr;
|
||||
mLastStackFromEnd = false;
|
||||
mStackFromEnd = false;
|
||||
mRecycleChildrenOnDetach = true;
|
||||
mAnchorInfo = new AnchorInfo();
|
||||
mLayoutChunkResult = new LayoutChunkResult();
|
||||
|
@ -157,7 +157,7 @@ public:
|
||||
int findLastCompletelyVisibleItemPosition();
|
||||
View* onFocusSearchFailed(View* focused, int focusDirection,
|
||||
RecyclerView::Recycler& recycler, RecyclerView::State& state);
|
||||
bool supportsPredictiveItemAnimations();
|
||||
bool supportsPredictiveItemAnimations()override;
|
||||
void prepareForDrop(View* view,View* target, int x, int y);
|
||||
};
|
||||
|
||||
|
@ -136,6 +136,7 @@ void RecyclerView::initRecyclerView(){
|
||||
mDataSetHasChangedAfterLayout = false;
|
||||
mEatenAccessibilityChangeFlags =0;
|
||||
mInterceptRequestLayoutDepth = 0;
|
||||
mAdapterUpdateDuringMeasure = false;
|
||||
mState = new State();
|
||||
mAdapterHelper = nullptr;
|
||||
mViewInfoStore = new ViewInfoStore();
|
||||
@ -332,7 +333,7 @@ void RecyclerView::initChildrenHelper() {
|
||||
if (!vh->isTmpDetached() && !vh->shouldIgnore()) {
|
||||
LOGE("Called attach on a child which is not detached: %p",vh);
|
||||
}
|
||||
LOGD_IF(_DEBUG,"reAttach %p",vh);
|
||||
LOGD_IF(_DEBUG,"reAttach %p %p:%d",vh,vh->itemView,vh->itemView->getId());
|
||||
vh->clearTmpDetachFlag();
|
||||
}
|
||||
attachViewToParent(child, index, layoutParams);
|
||||
@ -346,7 +347,7 @@ void RecyclerView::initChildrenHelper() {
|
||||
if (vh->isTmpDetached() && !vh->shouldIgnore()) {
|
||||
LOGE("called detach on an already detached child %p",vh);
|
||||
}
|
||||
LOGD_IF(_DEBUG,"tmpDetach =%p",vh);
|
||||
LOGD_IF(_DEBUG,"tmpDetach =%p %p:%d",vh,vh->itemView,vh->itemView->getId());
|
||||
vh->addFlags(ViewHolder::FLAG_TMP_DETACHED);
|
||||
}
|
||||
}
|
||||
@ -3795,7 +3796,24 @@ bool RecyclerView::Recycler::tryBindViewHolderByDeadline(ViewHolder& holder, int
|
||||
// abort - we have a deadline we can't meet
|
||||
return false;
|
||||
}
|
||||
// Holders being bound should be either fully attached or fully detached.
|
||||
// We don't want to bind with views that are temporarily detached, because that
|
||||
// creates a situation in which they are unable to reason about their attach state
|
||||
// properly.
|
||||
// For example, isAttachedToWindow will return true, but the itemView will lack a
|
||||
// parent. This breaks, among other possible issues, anything involving traversing
|
||||
// the view tree, such as ViewTreeLifecycleOwner.
|
||||
// Thus, we temporarily reattach any temp-detached holders for the bind operation.
|
||||
// See https://issuetracker.google.com/265347515 for additional details on problems
|
||||
// resulting from this
|
||||
bool reattachedForBind = false;
|
||||
if (holder.isTmpDetached()) {
|
||||
mRV->attachViewToParent(holder.itemView, mRV->getChildCount(), holder.itemView->getLayoutParams());
|
||||
reattachedForBind = true;
|
||||
}
|
||||
mRV->mAdapter->bindViewHolder(holder, offsetPosition);
|
||||
if(reattachedForBind)
|
||||
mRV->detachViewFromParent(holder.itemView);
|
||||
long endBindNs = mRV->getNanoTime();
|
||||
mRecyclerPool->factorInBindTime(holder.getItemViewType(), endBindNs - startBindNs);
|
||||
attachAccessibilityDelegateOnBind(holder);
|
||||
@ -4045,6 +4063,27 @@ void RecyclerView::Recycler::recycleView(View* view) {
|
||||
holder->clearReturnedFromScrapFlag();
|
||||
}
|
||||
recycleViewHolderInternal(*holder);
|
||||
// If the ViewHolder is running ItemAnimator, we want the recycleView() in scroll pass
|
||||
// to stop the ItemAnimator and put ViewHolder back in cache or Pool.
|
||||
// There are three situations:
|
||||
// 1. If the custom Adapter clears ViewPropertyAnimator in view detach like the
|
||||
// leanback (TV) app does, the ItemAnimator is likely to be stopped and
|
||||
// recycleViewHolderInternal will succeed.
|
||||
// 2. If the custom Adapter clears ViewPropertyAnimator, but the ItemAnimator uses
|
||||
// "pending runnable" and ViewPropertyAnimator has not started yet, the ItemAnimator
|
||||
// on the view will not be cleared. See b/73552923.
|
||||
// 3. If the custom Adapter does not clear ViewPropertyAnimator in view detach, the
|
||||
// ItemAnimator will not be cleared.
|
||||
// Since both 2&3 lead to failure of recycleViewHolderInternal(), we just explicitly end
|
||||
// the ItemAnimator, the callback of ItemAnimator.endAnimations() will recycle the View.
|
||||
//
|
||||
// Note the order: we must call endAnimation() after recycleViewHolderInternal()
|
||||
// to avoid recycle twice. If ViewHolder isRecyclable is false,
|
||||
// recycleViewHolderInternal() will not recycle it, endAnimation() will reset
|
||||
// isRecyclable flag and recycle the view.
|
||||
if (mRV->mItemAnimator && !holder->isRecyclable()) {
|
||||
mRV->mItemAnimator->endAnimation(*holder);
|
||||
}
|
||||
}
|
||||
|
||||
void RecyclerView::Recycler::recycleViewInternal(View* view) {
|
||||
@ -6253,10 +6292,10 @@ void RecyclerView::ViewHolder::setIsRecyclable(bool recyclable) {
|
||||
mIsRecyclableCount = recyclable ? mIsRecyclableCount - 1 : mIsRecyclableCount + 1;
|
||||
if (mIsRecyclableCount < 0) {
|
||||
mIsRecyclableCount = 0;
|
||||
LOGE_IF(_DEBUG,"isRecyclable decremented below 0: "
|
||||
"unmatched pair of setIsRecyable() calls for %p" , this);
|
||||
LOGE("isRecyclable decremented below 0: "
|
||||
"unmatched pair of setIsRecyable() calls for %p" , this);
|
||||
LOGE_IF(_DEBUG,"isRecyclable decremented to %d is below 0: "
|
||||
"unmatched pair of setIsRecyable() calls for %p" , mIsRecyclableCount,this);
|
||||
LOGE("isRecyclable decremented to %d is below 0: "
|
||||
"unmatched pair of setIsRecyable() calls for %p" ,mIsRecyclableCount, this);
|
||||
} else if (!recyclable && mIsRecyclableCount == 1) {
|
||||
mFlags |= FLAG_NOT_RECYCLABLE;
|
||||
} else if (recyclable && mIsRecyclableCount == 0) {
|
||||
@ -7035,7 +7074,8 @@ bool RecyclerView::ItemAnimator::canReuseUpdatedViewHolder(ViewHolder& viewHolde
|
||||
void RecyclerView::ItemAnimator::dispatchAnimationsFinished() {
|
||||
const int count = mFinishedListeners.size();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
mFinishedListeners.at(i)();//.onAnimationsFinished();
|
||||
auto ls = mFinishedListeners.at(i);
|
||||
if(ls)ls();//.onAnimationsFinished();
|
||||
}
|
||||
mFinishedListeners.clear();
|
||||
}
|
||||
|
@ -29,12 +29,12 @@ StaggeredGridLayoutManager::StaggeredGridLayoutManager(int spanCount, int orient
|
||||
|
||||
StaggeredGridLayoutManager::~StaggeredGridLayoutManager(){
|
||||
delete mPendingSavedState;
|
||||
delete mPrimaryOrientation;
|
||||
delete mSecondaryOrientation;
|
||||
delete mRemainingSpans;
|
||||
delete mAnchorInfo;
|
||||
delete mLazySpanLookup;
|
||||
delete mLayoutState;
|
||||
delete mPrimaryOrientation;
|
||||
delete mSecondaryOrientation;
|
||||
delete mRemainingSpans;
|
||||
delete mAnchorInfo;
|
||||
delete mLazySpanLookup;
|
||||
delete mLayoutState;
|
||||
}
|
||||
|
||||
void StaggeredGridLayoutManager::initLayoutManager(){
|
||||
|
Loading…
Reference in New Issue
Block a user