add adapterviewanimator and animatorinflater

This commit is contained in:
侯歌 2022-03-22 16:50:31 +08:00
parent fd9b4fa7af
commit 298fcab43e
19 changed files with 893 additions and 37 deletions

View File

@ -11,6 +11,7 @@ public:
}
void destroyItem(ViewGroup* container, int position,void* object)override{
container->removeView((View*)object);
delete (View*)object;
}
std::string getPageTitle(int position)override{
return std::string("Tab")+std::to_string(position);

View File

@ -21,6 +21,7 @@ public:
}
void destroyItem(ViewGroup* container, int position,void* object){
container->removeView((View*)object);
delete (View*)object;
}
float getPageWidth(int position){return 1.f;}//if returned calue <1 OffscreenPageLimit must be larger to workfine
};

View File

@ -52,6 +52,7 @@ public:
}
void destroyItem(ViewGroup* container, int position,void* object){
container->removeView((View*)object);
delete (View*)object;
}
};

View File

@ -36,6 +36,7 @@ public:
}
void destroyItem(ViewGroup* container, int position,void* object)override{
container->removeView((View*)object);
delete (View*)object;
}
float getPageWidth(int position)override{return 1.f;}

View File

@ -12,7 +12,14 @@
#include <fileadapter.h>
#include <R.h>
class FileTypeAdapter:public PagerAdapter{
private:
FileAdapter*adapter1 = nullptr;
FileAdapter*adapter2 = nullptr;
public:
~FileTypeAdapter(){
delete adapter1;
delete adapter2;
}
int getCount()override{return 5;}
bool isViewFromObject(View* view, void*object)override{ return view==object;}
void* instantiateItem(ViewGroup* container, int position)override{
@ -36,13 +43,13 @@ public:
ListView*lv=new ListView(800,480);
lv->setDivider(new ColorDrawable(0x80224422));
lv->setDividerHeight(1);
//lv->setFastScrollEnabled(true);
lv->setFastScrollEnabled(true);
lv->setSelector(new ColorDrawable(0x8800FF00));
lv->setVerticalScrollBarEnabled(true);
lv->setOverScrollMode(View::OVER_SCROLL_ALWAYS);
FileAdapter*adapter=new FileAdapter("@layout/fileitem.xml");
adapter->loadFiles("/");
lv->setAdapter(adapter);
adapter1=new FileAdapter("@layout/fileitem.xml");
adapter1->loadFiles("/");
lv->setAdapter(adapter1);
lv->setBackgroundColor(0xFF000000|(0xFF<<position*8));
container->addView(lv).setId(12345);
lv->setOnItemClickListener([](AdapterView&lv,View&v,int pos,long id){
@ -60,7 +67,7 @@ public:
}
case 1:{LOGD("===========1111");
GridView*gv=new GridView(800,480);
FileAdapter*adapter=new FileAdapter("@layout/fileitem2.xml");
adapter2=new FileAdapter("@layout/fileitem2.xml");
gv->setOnItemClickListener([](AdapterView&lv,View&v,int pos,long id){
FileAdapter*adp=(FileAdapter*)lv.getAdapter();
FileItem f=adp->getItemAt(pos);
@ -74,12 +81,12 @@ public:
gv->setVerticalScrollBarEnabled(true);
gv->setScrollbarFadingEnabled(false);
gv->setNumColumns(2);
gv->setAdapter(adapter);
gv->setAdapter(adapter2);
gv->setHorizontalSpacing(2);
gv->setVerticalSpacing(2);
container->addView(gv).setId(12345);
adapter->loadFiles("/");
adapter->notifyDataSetChanged();
adapter2->loadFiles("/");
adapter2->notifyDataSetChanged();
return gv;
}
}
@ -87,6 +94,7 @@ public:
void destroyItem(ViewGroup* container, int position,void* object)override{
container->removeView((View*)object);
LOGV("destroyItem[%d]: %p",position,object);
delete (View*)object;
}
std::string getPageTitle(int position)override{
return std::string("Tab")+std::to_string(position);
@ -108,6 +116,7 @@ protected:
public:
MediaWindow(int x,int y,int w,int h);
~MediaWindow(){
delete mAdapter;
player=nullptr;
}

View File

@ -0,0 +1,90 @@
#include <animation/animatorset.h>
#include <animation/animatorinflater.h>
#include <expat.h>
namespace cdroid{
Animator* AnimatorInflater::loadAnimator(Context* context,const std::string&resid){
return createAnimatorFromXml(context,resid);
}
StateListAnimator* AnimatorInflater::loadStateListAnimator(Context* context,const std::string&resid){
return createStateListAnimatorFromXml(context,resid);
}
typedef struct{
Context*context;
std::vector<Animator*>animators;
std::string package;
Animator*result;
std::function<ObjectAnimator*(Context*,const AttributeSet&)>fnObject;
std::function<ValueAnimator*(Context*,const AttributeSet&,ValueAnimator*)>fnAnimator;
}ParseData;
static void startElement(void *userData, const XML_Char *name, const XML_Char **satts){
ParseData*pd =(ParseData*)userData;
AttributeSet atts;
atts.setContext(pd->context,pd->package);
atts.set(satts);
Animator*anim = nullptr;
if(strcmp(name,"objectAnimator")==0){
anim = pd->fnObject(pd->context,atts);
}else if(strcmp(name,"animator")==0){
anim = pd->fnAnimator(pd->context,atts,nullptr);
}else if(strcmp(name,"set")==0){
anim = new AnimatorSet();
}else if(strcmp(name,"propertyValuesHolder")==0){
}else{
LOGE("Unknown animator name:%s",name);
}
if(pd->animators.empty())
pd->result = anim;
pd->animators.push_back(anim);
}
static void endElement(void *userData, const XML_Char *name){
ParseData*pd =(ParseData*)userData;
}
Animator* AnimatorInflater::createAnimatorFromXml(Context*ctx,const std::string&resid){
ParseData pd;
int len;
char buf[128];
XML_Parser parser=XML_ParserCreateNS(nullptr,' ');
pd.context = ctx;
pd.result = nullptr;
pd.fnObject = AnimatorInflater::loadObjectAnimator;
pd.fnAnimator= AnimatorInflater::loadValueAnimator;
std::unique_ptr<std::istream>stream=ctx->getInputStream(resid,&pd.package);
XML_SetUserData(parser,&pd);
XML_SetElementHandler(parser, startElement, endElement);
do {
stream->read(buf,sizeof(buf));
len=stream->gcount();
if (XML_Parse(parser, buf,len,len==0) == XML_STATUS_ERROR) {
const char*es=XML_ErrorString(XML_GetErrorCode(parser));
LOGE("%s at line %ld",es, XML_GetCurrentLineNumber(parser));
XML_ParserFree(parser);
return nullptr;
}
} while(len!=0);
XML_ParserFree(parser);
return pd.result;
}
StateListAnimator* AnimatorInflater::createStateListAnimatorFromXml(Context*ctx,const std::string&resid){
return nullptr;
}
ObjectAnimator* AnimatorInflater::loadObjectAnimator(Context*ctx,const AttributeSet& attrs){
ObjectAnimator*anim = new ObjectAnimator();
return anim;
}
ValueAnimator* AnimatorInflater::loadValueAnimator(Context*context,const AttributeSet& attrs, ValueAnimator*anim){
anim = new ValueAnimator();
return anim;
}
}

View File

@ -0,0 +1,23 @@
#ifndef __ANIMATOR_INFLATER_H__
#define __ANIMATOR_INFLATER_H__
#include <animation/objectanimator.h>
#include <animation/statelistanimator.h>
namespace cdroid{
class AnimatorInflater{
private:
static constexpr int VALUE_TYPE_FLOAT = 0;
static constexpr int VALUE_TYPE_INT = 1;
static constexpr int VALUE_TYPE_PATH = 2;
static constexpr int VALUE_TYPE_COLOR = 3;
static constexpr int VALUE_TYPE_UNDEFINED = 4;
private:
static Animator* createAnimatorFromXml(Context*ctx,const std::string&resid);
static StateListAnimator* createStateListAnimatorFromXml(Context*ctx,const std::string&resid);
static ObjectAnimator* loadObjectAnimator(Context*ctx,const AttributeSet& attrs);
static ValueAnimator* loadValueAnimator(Context*context,const AttributeSet& attrs, ValueAnimator*anim);
public:
static Animator* loadAnimator(Context* context,const std::string&resid);
static StateListAnimator* loadStateListAnimator(Context* context,const std::string&resid);
};
}//endof namespace
#endif

39
src/gui/core/graphdevice.cc Normal file → Executable file
View File

@ -36,12 +36,15 @@ GraphDevice::GraphDevice(int fmt){
GFXGetScreenSize((UINT*)&mScreenWidth,(UINT*)&mScreenHeight);
mFormat = fmt<0?GPF_ARGB:fmt;
GFXCreateSurface(&primarySurface,mScreenWidth,mScreenHeight,mFormat,1);
GFXLockSurface(primarySurface,(void**)&buffer,&pitch);
GFXCreateSurface(&mPrimarySurface,mScreenWidth,mScreenHeight,mFormat,1);
GFXLockSurface(mPrimarySurface,(void**)&buffer,&pitch);
GFXCreateSurface(&mBannerSurface,200,40,mFormat,0);
mLastComposeTime = SystemClock::uptimeMillis();
LOGD("primarySurface=%p size=%dx%d",primarySurface,mScreenWidth,mScreenHeight);
LOGD("PrimarySurface=%p size=%dx%d",mPrimarySurface,mScreenWidth,mScreenHeight);
RefPtr<Surface>surf=ImageSurface::create(buffer,Surface::Format::ARGB32,mScreenWidth,mScreenHeight,pitch);
primaryContext = new Canvas(surf);
mPrimaryContext = new Canvas(surf);
mInvalidateRgn = Region::create();
mComposing = 0;
mQuitFlag = false;
@ -53,13 +56,17 @@ GraphDevice::~GraphDevice(){
mQuitFlag = true;
mCV.notify_all();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
delete primaryContext;
GFXDestroySurface(primarySurface);
primarySurface = nullptr;
primaryContext = nullptr;
delete mPrimaryContext;
GFXDestroySurface(mPrimarySurface);
mPrimarySurface = nullptr;
mPrimaryContext = nullptr;
LOGD("%p Destroied",this);
}
HANDLE GraphDevice::getPrimarySurface()const{
return mPrimarySurface;
}
void GraphDevice::invalidate(const Rect&r){
mInvalidateRgn->do_union((const RectangleInt&)r);
}
@ -107,7 +114,7 @@ bool GraphDevice::needCompose(){
}
Canvas*GraphDevice::getPrimaryContext(){
return primaryContext;
return mPrimaryContext;
}
void GraphDevice::doCompose(){
@ -170,7 +177,7 @@ void GraphDevice::composeSurfaces(){
return false;
});
computeVisibleRegion(wins,winVisibleRgns);
primaryContext->set_operator(Cairo::Context::Operator::SOURCE);
mPrimaryContext->set_operator(Cairo::Context::Operator::SOURCE);
for(int i=0;i<wSurfaces.size();i++){
Rect rcw = wBounds[i];
RefPtr<Region> rgn = winVisibleRgns[i];
@ -185,23 +192,23 @@ void GraphDevice::composeSurfaces(){
rcc.intersect(0,0,mScreenWidth,mScreenHeight);
if(rcc.empty())continue;
if(hdlSurface)GFXBlit(primarySurface , rcw.left+rc.x , rcw.top+rc.y , hdlSurface,(const GFXRect*)&rc);
else primaryContext->rectangle(rcw.left+rc.x , rcw.top+rc.y, rc.width , rc.height);
if(hdlSurface)GFXBlit(mPrimarySurface , rcw.left+rc.x , rcw.top+rc.y , hdlSurface,(const GFXRect*)&rc);
else mPrimaryContext->rectangle(rcw.left+rc.x , rcw.top+rc.y, rc.width , rc.height);
}
if(hdlSurface==nullptr){
primaryContext->set_source(wSurfaces[i]->get_target(),rcw.left,rcw.top);
primaryContext->fill();
mPrimaryContext->set_source(wSurfaces[i]->get_target(),rcw.left,rcw.top);
mPrimaryContext->fill();
}
}
const RectangleInt rectScreen={0,0,mScreenWidth,mScreenHeight};
mInvalidateRgn->intersect(rectScreen);
for(int i=0;i<mInvalidateRgn->get_num_rectangles();i++){
RectangleInt r=mInvalidateRgn->get_rectangle(i);
GFXFillRect(primarySurface,(const GFXRect*)&r,0);
GFXFillRect(mPrimarySurface,(const GFXRect*)&r,0);
LOGV("%d:(%d,%d,%d,%d)",i,r.x,r.y,r.width,r.height);
}
mInvalidateRgn->do_xor(mInvalidateRgn);
GFXFlip(primarySurface);
GFXFlip(mPrimarySurface);
t2=SystemClock::uptimeMillis();
mLastComposeTime = SystemClock::uptimeMillis();
mPendingCompose = 0;

8
src/gui/core/graphdevice.h Normal file → Executable file
View File

@ -22,8 +22,10 @@ private:
uint64_t mFpsNumFrames;
std::mutex mMutex;
std::condition_variable mCV;
class Canvas*primaryContext;//
HANDLE primarySurface;
HANDLE mPrimarySurface;
HANDLE mBannerSurface;
class Canvas*mPrimaryContext;
Canvas *mBannerContext;
RefPtr<Region>mInvalidateRgn;
static GraphDevice*mInst;
GraphDevice(int format=-1);
@ -44,7 +46,7 @@ public:
bool needCompose();
Canvas*getPrimaryContext();
void invalidate(const Rect&);
HANDLE getPrimarySurface(){return primarySurface;}
HANDLE getPrimarySurface()const;
};
}
#endif

View File

@ -18,7 +18,7 @@ public:
}
void invalidateDrawable(Drawable& who)override{
// Ignore invalidation.
// Ignore invalidation.
}
void scheduleDrawable(Drawable& who,Runnable what, long when)override{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

2
src/gui/view/viewgroup.cc Normal file → Executable file
View File

@ -1068,7 +1068,7 @@ View& ViewGroup::addViewInner(View* child, int index,LayoutParams* params,bool p
} else {
child->mParent = this;
}
//if (child->hasUnhandledKeyListener()) incrementChildUnhandledKeyListeners();
if (child->hasUnhandledKeyListener()) incrementChildUnhandledKeyListeners();
bool childHasFocus = child->hasFocus();
if (childHasFocus) requestChildFocus(child, child->findFocus());

View File

@ -0,0 +1,584 @@
#include <widget/adapterviewanimator.h>
#include <animation/animatorinflater.h>
namespace cdroid{
DECLARE_WIDGET(AdapterViewAnimator)
AdapterViewAnimator::AdapterViewAnimator(Context* context,const AttributeSet& attrs)
:AdapterView(context,attrs){
initViewAnimator();
std::string res = attrs.getString("inAnimation");
if(res.empty())
setInAnimation(getDefaultInAnimation());
res = attrs.getString("outAnimation");
if(res.empty())
setOutAnimation(getDefaultOutAnimation());
const bool flag = attrs.getBoolean("animateFirstView",true);
setAnimateFirstView(flag);
mLoopViews = attrs.getBoolean("loopViews",false);
}
AdapterViewAnimator::~AdapterViewAnimator(){
delete mInAnimation;
delete mOutAnimation;
for(auto v:mViewsMap)
delete v.second;
mViewsMap.clear();
if(mDataSetObserver){
mAdapter->unregisterDataSetObserver(mDataSetObserver);
delete mDataSetObserver;
}
}
AdapterViewAnimator::ViewAndMetaData::ViewAndMetaData(View* view, int relativeIndex, int adapterPosition, long itemId) {
this->view = view;
this->relativeIndex = relativeIndex;
this->adapterPosition = adapterPosition;
this->itemId = itemId;
}
void AdapterViewAnimator::initViewAnimator(){
mInAnimation = nullptr;
mOutAnimation= nullptr;
mDataSetObserver = nullptr;
mPendingCheckForTap = [this](){
if (mTouchMode == TOUCH_MODE_DOWN_IN_CURRENT_VIEW) {
View* v = getCurrentView();
showTapFeedback(v);
}
};
}
void AdapterViewAnimator::configureViewAnimator(int numVisibleViews, int activeOffset){
if (activeOffset > numVisibleViews - 1) {
// Throw an exception here.
}
mMaxNumActiveViews = numVisibleViews;
mActiveOffset = activeOffset;
mPreviousViews.clear();
for(auto v:mViewsMap)
delete v.second;
mViewsMap.clear();
removeAllViewsInLayout();
mCurrentWindowStart = 0;
mCurrentWindowEnd = -1;
}
void AdapterViewAnimator::transformViewForTransition(int fromIndex, int toIndex, View* view, bool animate) {
if (fromIndex == -1) {
mInAnimation->setTarget(view);
mInAnimation->start();
} else if (toIndex == -1) {
mOutAnimation->setTarget(view);
mOutAnimation->start();
}
}
ObjectAnimator* AdapterViewAnimator::getDefaultInAnimation() {
ObjectAnimator* anim = ObjectAnimator::ofFloat(nullptr, "alpha",{0.0f, 1.0f});
anim->setDuration(DEFAULT_ANIMATION_DURATION);
return anim;
}
ObjectAnimator* AdapterViewAnimator::getDefaultOutAnimation() {
ObjectAnimator* anim = ObjectAnimator::ofFloat(nullptr, "alpha",{1.0f, 0.0f});
anim->setDuration(DEFAULT_ANIMATION_DURATION);
return anim;
}
void AdapterViewAnimator::setDisplayedChild(int whichChild){
setDisplayedChild(whichChild, true);
}
void AdapterViewAnimator::setDisplayedChild(int whichChild, bool animate) {
if (mAdapter != nullptr) {
mWhichChild = whichChild;
if (whichChild >= getWindowSize()) {
mWhichChild = mLoopViews ? 0 : getWindowSize() - 1;
} else if (whichChild < 0) {
mWhichChild = mLoopViews ? getWindowSize() - 1 : 0;
}
const bool hasFocus = getFocusedChild() != nullptr;
// This will clear old focus if we had it
showOnly(mWhichChild, animate);
if (hasFocus) {
// Try to retake focus if we had it
requestFocus(FOCUS_FORWARD);
}
}
}
void AdapterViewAnimator::applyTransformForChildAtIndex(View* child, int relativeIndex) {
//NOTHING
}
int AdapterViewAnimator::getDisplayedChild() {
return mWhichChild;
}
void AdapterViewAnimator::showNext(){
setDisplayedChild(mWhichChild + 1);
}
void AdapterViewAnimator::showPrevious(){
setDisplayedChild(mWhichChild - 1);
}
int AdapterViewAnimator::modulo(int pos, int size) {
if (size > 0) {
return (size + (pos % size)) % size;
} else {
return 0;
}
}
View* AdapterViewAnimator::getViewAtRelativeIndex(int relativeIndex){
if (relativeIndex >= 0 && relativeIndex <= getNumActiveViews() - 1 && mAdapter != nullptr) {
int i = modulo(mCurrentWindowStartUnbounded + relativeIndex, getWindowSize());
auto it=mViewsMap.find(i);
if (it!=mViewsMap.end()) {
return it->second->view;
}
}
return nullptr;
}
int AdapterViewAnimator::getNumActiveViews() {
if (mAdapter != nullptr) {
return std::min(getCount() + 1, mMaxNumActiveViews);
} else {
return mMaxNumActiveViews;
}
}
int AdapterViewAnimator::getWindowSize() {
if (mAdapter != nullptr) {
const int adapterCount = getCount();
if (adapterCount <= getNumActiveViews() && mLoopViews) {
return adapterCount*mMaxNumActiveViews;
} else {
return adapterCount;
}
} else {
return 0;
}
}
AdapterViewAnimator::ViewAndMetaData* AdapterViewAnimator::getMetaDataForChild(View* child){
for (auto it= mViewsMap.begin();it!=mViewsMap.end();it++) {
if (it->second->view == child) {
return it->second;
}
}
return nullptr;
}
LayoutParams* AdapterViewAnimator::createOrReuseLayoutParams(View* v) {
LayoutParams* currentLp = v->getLayoutParams();
if (currentLp != nullptr) {
return currentLp;
}
return new LayoutParams(0, 0);
}
void AdapterViewAnimator::refreshChildren() {
if (mAdapter == nullptr) return;
for (int i = mCurrentWindowStart; i <= mCurrentWindowEnd; i++) {
int index = modulo(i, getWindowSize());
int adapterCount = getCount();
// get the fresh child from the adapter
View* updatedChild = mAdapter->getView(modulo(i, adapterCount), nullptr, this);
/*if (updatedChild->getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
updatedChild->setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}*/
auto it = mViewsMap.find(index);
if (mViewsMap.end()!=it) {
FrameLayout* fl = (FrameLayout*) it->second->view;
// add the new child to the frame, if it exists
if (updatedChild != nullptr) {
// flush out the old child
fl->removeAllViewsInLayout();
fl->addView(updatedChild);
}
}
}
}
FrameLayout* AdapterViewAnimator::getFrameForChild() {
return new FrameLayout(mContext,AttributeSet());
}
void AdapterViewAnimator::showOnly(int childIndex, bool animate) {
if (mAdapter == nullptr) return;
const int adapterCount = getCount();
if (adapterCount == 0) return;
for (int i = 0; i < mPreviousViews.size(); i++) {
auto it = mViewsMap.find(mPreviousViews.at(i));
View* viewToRemove = it->second->view;
mViewsMap.erase(it);
delete it->second;
viewToRemove->clearAnimation();
if (dynamic_cast<ViewGroup*>(viewToRemove)) {
ViewGroup* vg = (ViewGroup*) viewToRemove;
vg->removeAllViewsInLayout();
}
// applyTransformForChildAtIndex here just allows for any cleanup
// associated with this view that may need to be done by a subclass
applyTransformForChildAtIndex(viewToRemove, -1);
removeViewInLayout(viewToRemove);
}
mPreviousViews.clear();
int newWindowStartUnbounded = childIndex - mActiveOffset;
int newWindowEndUnbounded = newWindowStartUnbounded + getNumActiveViews() - 1;
int newWindowStart = std::max(0, newWindowStartUnbounded);
int newWindowEnd = std::min(adapterCount - 1, newWindowEndUnbounded);
if (mLoopViews) {
newWindowStart = newWindowStartUnbounded;
newWindowEnd = newWindowEndUnbounded;
}
int rangeStart = modulo(newWindowStart, getWindowSize());
int rangeEnd = modulo(newWindowEnd, getWindowSize());
bool wrap = false;
if (rangeStart > rangeEnd) {
wrap = true;
}
// This section clears out any items that are in our active views list
// but are outside the effective bounds of our window (this is becomes an issue
// at the extremities of the list, eg. where newWindowStartUnbounded < 0 or
// newWindowEndUnbounded > adapterCount - 1
for (auto vm : mViewsMap) {
int index=vm.first;
bool remove = false;
if (!wrap && (index < rangeStart || index > rangeEnd)) {
remove = true;
} else if (wrap && (index > rangeEnd && index < rangeStart)) {
remove = true;
}
if (remove) {
View* previousView = vm.second->view;
int oldRelativeIndex = vm.second->relativeIndex;
mPreviousViews.push_back(index);
transformViewForTransition(oldRelativeIndex, -1, previousView, animate);
}
}
// If the window has changed
if (!(newWindowStart == mCurrentWindowStart && newWindowEnd == mCurrentWindowEnd &&
newWindowStartUnbounded == mCurrentWindowStartUnbounded)) {
// Run through the indices in the new range
for (int i = newWindowStart; i <= newWindowEnd; i++) {
int index = modulo(i, getWindowSize());
int oldRelativeIndex;
auto it=mViewsMap.find(index);
if (it!=mViewsMap.end()) {
oldRelativeIndex = it->second->relativeIndex;
} else {
oldRelativeIndex = -1;
}
int newRelativeIndex = i - newWindowStartUnbounded;
// If this item is in the current window, great, we just need to apply
// the transform for it's new relative position in the window, and animate
// between it's current and new relative positions
bool inOldRange = it!=mViewsMap.end()&& std::find(mPreviousViews.begin(),
mPreviousViews.end(),index)==mPreviousViews.end();
if (inOldRange) {
View* view = it->second->view;
it->second->relativeIndex = newRelativeIndex;
applyTransformForChildAtIndex(view, newRelativeIndex);
transformViewForTransition(oldRelativeIndex, newRelativeIndex, view, animate);
// Otherwise this view is new to the window
} else {
// Get the new view from the adapter, add it and apply any transform / animation
const int adapterPosition = modulo(i, adapterCount);
View* newView = mAdapter->getView(adapterPosition, nullptr, this);
long itemId = mAdapter->getItemId(adapterPosition);
// We wrap the new view in a FrameLayout so as to respect the contract
// with the adapter, that is, that we don't modify this view directly
FrameLayout* fl = getFrameForChild();
// If the view from the adapter is null, we still keep an empty frame in place
if (newView != nullptr) {
fl->addView(newView);
}
mViewsMap.insert(std::pair<int,ViewAndMetaData*>(index, new ViewAndMetaData(fl, newRelativeIndex,
adapterPosition, itemId)));
addChild(fl);
applyTransformForChildAtIndex(fl, newRelativeIndex);
transformViewForTransition(-1, newRelativeIndex, fl, animate);
}
mViewsMap[index]->view->bringToFront();
}
mCurrentWindowStart = newWindowStart;
mCurrentWindowEnd = newWindowEnd;
mCurrentWindowStartUnbounded = newWindowStartUnbounded;
/*if (mRemoteViewsAdapter != nullptr) {
int adapterStart = modulo(mCurrentWindowStart, adapterCount);
int adapterEnd = modulo(mCurrentWindowEnd, adapterCount);
mRemoteViewsAdapter.setVisibleRangeHint(adapterStart, adapterEnd);
}*/
}
requestLayout();
invalidate();
}
void AdapterViewAnimator::addChild(View* child) {
addViewInLayout(child, -1, createOrReuseLayoutParams(child));
// This code is used to obtain a reference width and height of a child in case we need
// to decide our own size. TODO: Do we want to update the size of the child that we're
// using for reference size? If so, when?
if (mReferenceChildWidth == -1 || mReferenceChildHeight == -1) {
const int measureSpec = MeasureSpec::makeMeasureSpec(0, MeasureSpec::UNSPECIFIED);
child->measure(measureSpec, measureSpec);
mReferenceChildWidth = child->getMeasuredWidth();
mReferenceChildHeight = child->getMeasuredHeight();
}
}
void AdapterViewAnimator::showTapFeedback(View* v) {
v->setPressed(true);
}
void AdapterViewAnimator::hideTapFeedback(View* v) {
v->setPressed(false);
}
void AdapterViewAnimator::cancelHandleClick() {
View* v = getCurrentView();
if (v != nullptr) {
hideTapFeedback(v);
}
mTouchMode = TOUCH_MODE_NONE;
}
bool AdapterViewAnimator::onTouchEvent(MotionEvent& ev){
int action = ev.getAction();
bool handled = false;
View*v =nullptr;
switch (action) {
case MotionEvent::ACTION_DOWN:
if (v=getCurrentView()) {
if (isTransformedTouchPointInView(ev.getX(), ev.getY(), *v, nullptr)) {
mTouchMode = TOUCH_MODE_DOWN_IN_CURRENT_VIEW;
postDelayed(mPendingCheckForTap, ViewConfiguration::getTapTimeout());
}
}
break;
case MotionEvent::ACTION_MOVE: break;
case MotionEvent::ACTION_POINTER_UP: break;
case MotionEvent::ACTION_UP:
if (mTouchMode == TOUCH_MODE_DOWN_IN_CURRENT_VIEW) {
v = getCurrentView();
ViewAndMetaData* viewData = getMetaDataForChild(v);
if (v != nullptr) {
if (isTransformedTouchPointInView(ev.getX(), ev.getY(), *v, nullptr)) {
removeCallbacks(mPendingCheckForTap);
showTapFeedback(v);
postDelayed([this,viewData,v](){
if (viewData != nullptr)
performItemClick(v, viewData->adapterPosition,viewData->itemId);
else performItemClick(v, 0, 0);
},ViewConfiguration::getPressedStateDuration());
handled = true;
}
}
}
mTouchMode = TOUCH_MODE_NONE;
break;
case MotionEvent::ACTION_CANCEL:
v = getCurrentView();
if (v != nullptr) {
hideTapFeedback(v);
}
mTouchMode = TOUCH_MODE_NONE;
}
return handled;
}
void AdapterViewAnimator::measureChildren() {
const int count = getChildCount();
int childWidth = getMeasuredWidth() - mPaddingLeft - mPaddingRight;
int childHeight = getMeasuredHeight() - mPaddingTop - mPaddingBottom;
for (int i = 0; i < count; i++) {
View* child = getChildAt(i);
child->measure(MeasureSpec::makeMeasureSpec(childWidth, MeasureSpec::EXACTLY),
MeasureSpec::makeMeasureSpec(childHeight, MeasureSpec::EXACTLY));
}
}
void AdapterViewAnimator::onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecSize = MeasureSpec::getSize(widthMeasureSpec);
int heightSpecSize = MeasureSpec::getSize(heightMeasureSpec);
int widthSpecMode = MeasureSpec::getMode(widthMeasureSpec);
int heightSpecMode = MeasureSpec::getMode(heightMeasureSpec);
bool haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1);
// We need to deal with the case where our parent hasn't told us how
// big we should be. In this case we try to use the desired size of the first
// child added.
if (heightSpecMode == MeasureSpec::UNSPECIFIED) {
heightSpecSize = haveChildRefSize ? mReferenceChildHeight + mPaddingTop +
mPaddingBottom : 0;
} else if (heightSpecMode == MeasureSpec::AT_MOST) {
if (haveChildRefSize) {
int height = mReferenceChildHeight + mPaddingTop + mPaddingBottom;
if (height > heightSpecSize) {
heightSpecSize |= MEASURED_STATE_TOO_SMALL;
} else {
heightSpecSize = height;
}
}
}
if (widthSpecMode == MeasureSpec::UNSPECIFIED) {
widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
mPaddingRight : 0;
} else if (heightSpecMode == MeasureSpec::AT_MOST) {
if (haveChildRefSize) {
int width = mReferenceChildWidth + mPaddingLeft + mPaddingRight;
if (width > widthSpecSize) {
widthSpecSize |= MEASURED_STATE_TOO_SMALL;
} else {
widthSpecSize = width;
}
}
}
setMeasuredDimension(widthSpecSize, heightSpecSize);
measureChildren();
}
void AdapterViewAnimator::checkForAndHandleDataChanged() {
bool dataChanged = mDataChanged;
if (dataChanged) {
post([this](){
handleDataChanged();
// if the data changes, mWhichChild might be out of the bounds of the adapter
// in this case, we reset mWhichChild to the beginning
if (mWhichChild >= getWindowSize()) {
mWhichChild = 0;
showOnly(mWhichChild, false);
} else if (mOldItemCount != getCount()) {
showOnly(mWhichChild, false);
}
refreshChildren();
requestLayout();
});
}
mDataChanged = false;
}
void AdapterViewAnimator::onLayout(bool changed, int left, int top, int width, int height) {
checkForAndHandleDataChanged();
const int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View* child = getChildAt(i);
const int childWidth = child->getMeasuredWidth();
const int childHeight= child->getMeasuredHeight();
child->layout(mPaddingLeft, mPaddingTop, childWidth, childHeight);
}
}
View* AdapterViewAnimator::getCurrentView(){
return getViewAtRelativeIndex(mActiveOffset);
}
ObjectAnimator* AdapterViewAnimator::getInAnimation() {
return mInAnimation;
}
ObjectAnimator* AdapterViewAnimator::getOutAnimation() {
return mOutAnimation;
}
void AdapterViewAnimator::setInAnimation(ObjectAnimator* inAnimation) {
mInAnimation=inAnimation;
}
void AdapterViewAnimator::setOutAnimation(ObjectAnimator* outAnimation) {
mInAnimation=outAnimation;
}
void AdapterViewAnimator::setInAnimation(Context* context, const std::string&resourceID) {
setInAnimation((ObjectAnimator*) AnimatorInflater::loadAnimator(context, resourceID));
}
void AdapterViewAnimator::setOutAnimation(Context* context, const std::string&resourceID) {
setOutAnimation((ObjectAnimator*) AnimatorInflater::loadAnimator(context, resourceID));
}
void AdapterViewAnimator::setAnimateFirstView(bool animate) {
mAnimateFirstTime = animate;
}
int AdapterViewAnimator::getBaseline() {
return getCurrentView() ? getCurrentView()->getBaseline() : AdapterView::getBaseline();
}
Adapter* AdapterViewAnimator::getAdapter() {
return mAdapter;
}
void AdapterViewAnimator::setAdapter(Adapter* adapter) {
if (mAdapter != nullptr && mDataSetObserver != nullptr) {
mAdapter->unregisterDataSetObserver(mDataSetObserver);
delete mDataSetObserver;
}
mAdapter = adapter;
checkFocus();
if (mAdapter != nullptr) {
mDataSetObserver = new AdapterDataSetObserver(this);
mAdapter->registerDataSetObserver(mDataSetObserver);
mItemCount = mAdapter->getCount();
}
setFocusable(true);
mWhichChild = 0;
showOnly(mWhichChild, false);
}
void AdapterViewAnimator::setSelection(int position) {
setDisplayedChild(position);
}
View* AdapterViewAnimator::getSelectedView() {
return getViewAtRelativeIndex(mActiveOffset);
}
/**
* This defers a notifyDataSetChanged on the pending RemoteViewsAdapter if it has not
* connected yet.*/
void AdapterViewAnimator::deferNotifyDataSetChanged() {
mDeferNotifyDataSetChanged = true;
}
void AdapterViewAnimator::advance() {
showNext();
}
}//endof namespace

View File

@ -0,0 +1,141 @@
#ifndef __ADAPTERVIEW_ANIMATOR_H__
#define __ADAPTERVIEW_ANIMATOR_H__
#include <widget/adapterview.h>
#include <widget/framelayout.h>
namespace cdroid{
class AdapterViewAnimator:public AdapterView{
private:
static constexpr int DEFAULT_ANIMATION_DURATION = 200;
/* Private touch states.*/
static constexpr int TOUCH_MODE_NONE = 0;
static constexpr int TOUCH_MODE_DOWN_IN_CURRENT_VIEW = 1;
static constexpr int TOUCH_MODE_HANDLED = 2;
int mRestoreWhichChild = -1;
/* Current touch state.*/
Runnable mPendingCheckForTap;
int mTouchMode = TOUCH_MODE_NONE;
class ViewAndMetaData {
public:
View* view;
int relativeIndex;
int adapterPosition;
long itemId;
public:
ViewAndMetaData(View* view, int relativeIndex, int adapterPosition, long itemId);
};
protected:
int mWhichChild = 0;
/* The index of the child to restore after the asynchronous connection from the
* RemoteViewsAdapter has been. */
/* Whether or not the first view(s) should be animated in*/
bool mAnimateFirstTime = true;
/* Represents where the in the current window of
* views the current <code>mDisplayedChild</code> sits */
int mActiveOffset = 0;
/**The number of views that the {@link AdapterViewAnimator} keeps as children at any
* given time (not counting views that are pending removal, see {@link #mPreviousViews}). */
int mMaxNumActiveViews = 1;
/* Map of the children of the {@link AdapterViewAnimator}.*/
std::map<int, ViewAndMetaData*> mViewsMap;
/* List of views pending removal from the {@link AdapterViewAnimator}*/
std::vector<int> mPreviousViews;
/* The index, relative to the adapter, of the beginning of the window of views */
int mCurrentWindowStart = 0;
/* The index, relative to the adapter, of the end of the window of views */
int mCurrentWindowEnd = -1;
/* The same as {@link #mCurrentWindowStart}, except when the we have bounded
* {@link #mCurrentWindowStart} to be non-negative */
int mCurrentWindowStartUnbounded = 0;
/* Listens for data changes from the adapter */
DataSetObserver* mDataSetObserver;
/* The {@link Adapter} for this {@link AdapterViewAnimator} */
Adapter* mAdapter;
/* The {@link RemoteViewsAdapter} for this {@link AdapterViewAnimator}*/
//RemoteViewsAdapter mRemoteViewsAdapter;
/* The remote adapter containing the data to be displayed by this view to be set */
bool mDeferNotifyDataSetChanged = false;
/* Specifies whether this is the first time the animator is showing views */
bool mFirstTime = true;
/* Specifies if the animator should wrap from 0 to the end and vice versa
* or have hard boundaries at the beginning and end */
bool mLoopViews = true;
/* The width and height of some child, used as a size reference in-case our
* dimensions are unspecified by the parent. */
int mReferenceChildWidth = -1;
int mReferenceChildHeight = -1;
/* In and out animations. */
ObjectAnimator* mInAnimation;
ObjectAnimator* mOutAnimation;
private:
void initViewAnimator();
void setDisplayedChild(int whichChild, bool animate);
ViewAndMetaData* getMetaDataForChild(View* child);
void addChild(View* child);
void measureChildren();
protected:
void configureViewAnimator(int numVisibleViews, int activeOffset);
void transformViewForTransition(int fromIndex, int toIndex, View* view, bool animate);
ObjectAnimator* getDefaultInAnimation();
ObjectAnimator* getDefaultOutAnimation();
void applyTransformForChildAtIndex(View* child, int relativeIndex);
int modulo(int pos, int size);
View* getViewAtRelativeIndex(int relativeIndex);
int getNumActiveViews();
int getWindowSize();
LayoutParams* createOrReuseLayoutParams(View* v);
void refreshChildren();
FrameLayout* getFrameForChild();
void showOnly(int childIndex, bool animate);
void showTapFeedback(View* v);
void hideTapFeedback(View* v);
void cancelHandleClick();
void onMeasure(int widthMeasureSpec, int heightMeasureSpec)override;
void checkForAndHandleDataChanged();
void onLayout(bool changed, int left, int top, int width, int height)override;
public:
AdapterViewAnimator(Context* context,const AttributeSet& attrs);
~AdapterViewAnimator()override;
void setDisplayedChild(int whichChild);
int getDisplayedChild();
void showNext();
void showPrevious();
bool onTouchEvent(MotionEvent& ev)override;
View* getCurrentView();
ObjectAnimator* getInAnimation();
void setInAnimation(ObjectAnimator* inAnimation);
ObjectAnimator* getOutAnimation();
void setOutAnimation(ObjectAnimator* outAnimation);
void setInAnimation(Context* context,const std::string& resourceID);
void setOutAnimation(Context* context,const std::string& resourceID);
void setAnimateFirstView(bool animate);
int getBaseline()override;
Adapter* getAdapter()override;
void setAdapter(Adapter* adapter)override;
void setSelection(int position)override;
View* getSelectedView()override;
void deferNotifyDataSetChanged();
void advance();
};
}//namepace
#endif

8
src/gui/widget/recyclebin.cc Normal file → Executable file
View File

@ -352,9 +352,9 @@ View* RecycleBin::retrieveFromScrap(std::vector<View*>& scrapViews, int position
if (LV->mAdapterHasStableIds) {
long id = getAdapter()->getItemId(position);
if (id == params->itemId) {
View*scrap=scrapViews[i];
View*scrap=scrapViews[i];
scrapViews.erase(scrapViews.begin()+i);//remove(i);
return scrap;
return scrap;
}
} else if (params->scrappedFromPosition == position) {
View* scrap = scrapViews[i];
@ -375,8 +375,8 @@ View* RecycleBin::retrieveFromScrap(std::vector<View*>& scrapViews, int position
void RecycleBin::clearScrap(std::vector<View*>& scrap) {
int scrapCount = scrap.size();
for (int j = 0; j < scrapCount; j++) {
View*v=scrap[scrapCount - 1 - j];
scrap.erase(scrap.begin()+scrapCount - 1 - j);
View*v=scrap[scrapCount - 1 - j];
scrap.erase(scrap.begin()+scrapCount - 1 - j);
removeDetachedView(v, false);
}
}

View File

@ -111,7 +111,6 @@ void ViewPager::setAdapter(PagerAdapter* adapter){
for (int i = 0; i < mItems.size(); i++) {
ItemInfo* ii = mItems[i];
mAdapter->destroyItem(this, ii->position, ii->object);
delete (View*)ii->object;//added by zhhou
}
mAdapter->finishUpdate(this);
mItems.clear();
@ -474,7 +473,6 @@ void ViewPager::dataSetChanged(){
}
mAdapter->destroyItem(this, ii->position, ii->object);
delete (View*)ii->object;//added by zhhou
needPopulate = true;
if (mCurItem == ii->position) { // Keep the current item in the valid range
@ -583,7 +581,6 @@ void ViewPager::populate(int newCurrentItem){
if (pos == ii->position && !ii->scrolling) {
mItems.erase(mItems.begin()+itemIndex);
mAdapter->destroyItem(this, pos, ii->object);
delete (View*)ii->object;//added by zhhou
LOGD("destroyItem() with pos:%d/%d view:%p curitem=%d/%d",pos,ii->position,ii->object,mCurItem,mItems.size());
itemIndex--;
curIndex--;
@ -615,7 +612,6 @@ void ViewPager::populate(int newCurrentItem){
if (pos == ii->position && !ii->scrolling) {
mItems.erase(mItems.begin()+itemIndex);
mAdapter->destroyItem(this, pos, ii->object);
delete (View*)ii->object;//added by zhhou
ii = itemIndex < mItems.size() ? mItems[itemIndex] : nullptr;
}
} else if (ii != nullptr && pos == ii->position) {