mirror of
https://gitee.com/houstudio/Cdroid.git
synced 2024-12-04 05:10:06 +08:00
adviewpager2
This commit is contained in:
parent
021ec5c3d9
commit
73cf7c2015
944
src/gui/widgetEx/viewpager2.cc
Executable file
944
src/gui/widgetEx/viewpager2.cc
Executable file
@ -0,0 +1,944 @@
|
||||
#include <widgetEx/viewpager2.h>
|
||||
#include <widgetEx/recyclerview/pagersnaphelper.h>
|
||||
#include <widgetEx/scrolleventadapter.h>
|
||||
#include <widgetEx/fakedrag.h>
|
||||
#include <widgetEx/compositeonpagechangecallback.h>
|
||||
namespace cdroid{
|
||||
class PageTransformerAdapter:public ViewPager2::OnPageChangeCallback {
|
||||
private:
|
||||
LinearLayoutManager* mLayoutManager;
|
||||
ViewPager2::PageTransformer* mPageTransformer;
|
||||
public:
|
||||
PageTransformerAdapter(LinearLayoutManager* layoutManager) {
|
||||
mLayoutManager = layoutManager;
|
||||
onPageScrolled = std::bind(&PageTransformerAdapter::doPageScrolled,this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
}
|
||||
ViewPager2::PageTransformer* getPageTransformer() {
|
||||
return mPageTransformer;
|
||||
}
|
||||
|
||||
void setPageTransformer(ViewPager2::PageTransformer* transformer) {
|
||||
mPageTransformer = transformer;
|
||||
}
|
||||
|
||||
void doPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mPageTransformer != nullptr) {
|
||||
const float transformOffset = -positionOffset;
|
||||
for(int i = 0; i < mLayoutManager->getChildCount(); ++i) {
|
||||
View* view = mLayoutManager->getChildAt(i);
|
||||
FATAL_IF(view==nullptr,"LayoutManager returned a null child at pos %d/%d while transforming pages", i, mLayoutManager->getChildCount());
|
||||
const int currPos = mLayoutManager->getPosition(view);
|
||||
const float viewOffset = transformOffset + (float)(currPos - position);
|
||||
mPageTransformer->transformPage(*view, viewOffset);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ViewPager2::ViewPager2(Context* context,const AttributeSet& attrs)
|
||||
:ViewGroup(context, attrs){
|
||||
initialize(context, attrs);
|
||||
}
|
||||
|
||||
void ViewPager2::initialize(Context* context,const AttributeSet& attrs) {
|
||||
/*mAccessibilityProvider = sFeatureEnhancedA11yEnabled
|
||||
? new PageAwareAccessibilityProvider()
|
||||
: new BasicAccessibilityProvider();*/
|
||||
|
||||
mRecyclerView = new RecyclerViewImpl(context,attrs);
|
||||
mRecyclerView->mVP =this;
|
||||
mRecyclerView->setId(View::generateViewId());
|
||||
mRecyclerView->setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
|
||||
|
||||
mLayoutManager = new LinearLayoutManagerImpl(context,this);
|
||||
mRecyclerView->setLayoutManager(mLayoutManager);
|
||||
mRecyclerView->setScrollingTouchSlop(RecyclerView::TOUCH_SLOP_PAGING);
|
||||
setOrientation(context, attrs);
|
||||
|
||||
mRecyclerView->setLayoutParams(
|
||||
new ViewGroup::LayoutParams(LayoutParams::MATCH_PARENT, LayoutParams::MATCH_PARENT));
|
||||
RecyclerView::OnChildAttachStateChangeListener ls;
|
||||
ls.onChildViewAttachedToWindow=[](View&view){
|
||||
RecyclerView::LayoutParams* layoutParams = (RecyclerView::LayoutParams*) view.getLayoutParams();
|
||||
if (layoutParams->width != LayoutParams::MATCH_PARENT
|
||||
|| layoutParams->height != LayoutParams::MATCH_PARENT) {
|
||||
FATAL("Pages must fill the whole ViewPager2 (use match_parent)");
|
||||
}
|
||||
};
|
||||
ls.onChildViewDetachedFromWindow=[](View&){
|
||||
// nothing
|
||||
};
|
||||
mRecyclerView->addOnChildAttachStateChangeListener(ls);//enforceChildFillListener());
|
||||
|
||||
// Create ScrollEventAdapter before attaching PagerSnapHelper to RecyclerView, because the
|
||||
// attach process calls PagerSnapHelperImpl.findSnapView, which uses the mScrollEventAdapter
|
||||
mScrollEventAdapter = new ScrollEventAdapter(this);
|
||||
// Create FakeDrag before attaching PagerSnapHelper, same reason as above
|
||||
mFakeDragger = new FakeDrag(this, mScrollEventAdapter, mRecyclerView);
|
||||
mPagerSnapHelper = new PagerSnapHelperImpl();
|
||||
mPagerSnapHelper->attachToRecyclerView(mRecyclerView);
|
||||
// Add mScrollEventAdapter after attaching mPagerSnapHelper to mRecyclerView, because we
|
||||
// don't want to respond on the events sent out during the attach process
|
||||
mRecyclerView->addOnScrollListener(*mScrollEventAdapter);
|
||||
|
||||
mPageChangeEventDispatcher = new CompositeOnPageChangeCallback(3);
|
||||
mScrollEventAdapter->setOnPageChangeCallback(*mPageChangeEventDispatcher);
|
||||
|
||||
// Callback that updates mCurrentItem after swipes. Also triggered in other cases, but in
|
||||
// all those cases mCurrentItem will only be overwritten with the same value.
|
||||
OnPageChangeCallback currentItemUpdater;// = new OnPageChangeCallback() {
|
||||
currentItemUpdater.onPageSelected=[this](int position) {
|
||||
if (mCurrentItem != position) {
|
||||
mCurrentItem = position;
|
||||
//mAccessibilityProvider.onSetNewCurrentItem();
|
||||
}
|
||||
};
|
||||
|
||||
currentItemUpdater.onPageScrollStateChanged=[this](int newState) {
|
||||
if (newState == SCROLL_STATE_IDLE) {
|
||||
updateCurrentItem();
|
||||
}
|
||||
};
|
||||
|
||||
// Prevents focus from remaining on a no-longer visible page
|
||||
OnPageChangeCallback focusClearer;// = new OnPageChangeCallback() {
|
||||
focusClearer.onPageSelected=[this](int position) {
|
||||
clearFocus();
|
||||
if (hasFocus()) { // if clear focus did not succeed
|
||||
mRecyclerView->requestFocus(View::FOCUS_FORWARD);
|
||||
}
|
||||
};
|
||||
|
||||
// Add currentItemUpdater before mExternalPageChangeCallbacks, because we need to update
|
||||
// internal state first
|
||||
mPageChangeEventDispatcher->addOnPageChangeCallback(currentItemUpdater);
|
||||
mPageChangeEventDispatcher->addOnPageChangeCallback(focusClearer);
|
||||
// Allow a11y to register its listeners after currentItemUpdater (so it has the
|
||||
// right data). TODO: replace ordering comments with a test.
|
||||
//mAccessibilityProvider->onInitialize(mPageChangeEventDispatcher, mRecyclerView);
|
||||
mPageChangeEventDispatcher->addOnPageChangeCallback(*mExternalPageChangeCallbacks);
|
||||
|
||||
// Add mPageTransformerAdapter after mExternalPageChangeCallbacks, because page transform
|
||||
// events must be fired after scroll events
|
||||
mPageTransformerAdapter = new PageTransformerAdapter(mLayoutManager);
|
||||
mPageChangeEventDispatcher->addOnPageChangeCallback(*mPageTransformerAdapter);
|
||||
|
||||
attachViewToParent(mRecyclerView, 0, mRecyclerView->getLayoutParams());
|
||||
}
|
||||
|
||||
#if 0
|
||||
RecyclerView::OnChildAttachStateChangeListener ViewPager2::enforceChildFillListener() {
|
||||
return nullptr;/*new RecyclerView::OnChildAttachStateChangeListener() {
|
||||
public void onChildViewAttachedToWindow(View* view) {
|
||||
RecyclerView::LayoutParams* layoutParams = (RecyclerView::LayoutParams*) view->getLayoutParams();
|
||||
if (layoutParams->width != LayoutParams::MATCH_PARENT
|
||||
|| layoutParams->height != LayoutParams::MATCH_PARENT) {
|
||||
FATAL("Pages must fill the whole ViewPager2 (use match_parent)");
|
||||
}
|
||||
}
|
||||
|
||||
public void onChildViewDetachedFromWindow(View* view) {
|
||||
// nothing
|
||||
}
|
||||
};*/
|
||||
}
|
||||
CharSequence ViewPager2::getAccessibilityClassName() {
|
||||
if (mAccessibilityProvider.handlesGetAccessibilityClassName()) {
|
||||
return mAccessibilityProvider.onGetAccessibilityClassName();
|
||||
}
|
||||
return super.getAccessibilityClassName();
|
||||
}
|
||||
#endif
|
||||
|
||||
void ViewPager2::setOrientation(Context* context,const AttributeSet& attrs) {
|
||||
setOrientation(ORIENTATION_HORIZONTAL);
|
||||
//a.getInt(R.styleable.ViewPager2_android_orientation, ORIENTATION_HORIZONTAL));
|
||||
}
|
||||
#if 0
|
||||
Parcelable* ViewPager2::onSaveInstanceState() {
|
||||
Parcelable* superState = ViewGroup::onSaveInstanceState();
|
||||
SavedState* ss = new SavedState(*superState);
|
||||
|
||||
ss->mRecyclerViewId = mRecyclerView->getId();
|
||||
ss->mCurrentItem = mPendingCurrentItem == RecyclerView::NO_POSITION ? mCurrentItem : mPendingCurrentItem;
|
||||
|
||||
if (mPendingAdapterState != nullptr) {
|
||||
ss->mAdapterState = mPendingAdapterState;
|
||||
} else {
|
||||
RecyclerView::Adapter*adapter = mRecyclerView->getAdapter();
|
||||
/*if (adapter instanceof StatefulAdapter) {
|
||||
ss->mAdapterState = ((StatefulAdapter) adapter).saveState();
|
||||
}*/
|
||||
}
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
void ViewPager2::onRestoreInstanceState(Parcelable& state) {
|
||||
if ((dynamic_cast<SavedState*>(&state))==nullptr) {
|
||||
ViewGroup::onRestoreInstanceState(state);
|
||||
return;
|
||||
}
|
||||
|
||||
SavedState& ss = (SavedState&) state;
|
||||
//ViewGroup::onRestoreInstanceState(ss.getSuperState());
|
||||
mPendingCurrentItem = ss.mCurrentItem;
|
||||
mPendingAdapterState = ss.mAdapterState;
|
||||
}
|
||||
#endif
|
||||
void ViewPager2::restorePendingState() {
|
||||
if (mPendingCurrentItem == RecyclerView::NO_POSITION) {
|
||||
// No state to restore, or state is already restored
|
||||
return;
|
||||
}
|
||||
RecyclerView::Adapter*adapter = getAdapter();
|
||||
if (adapter == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (mPendingAdapterState != nullptr) {
|
||||
/*if (adapter instanceof StatefulAdapter) {
|
||||
((StatefulAdapter) adapter).restoreState(mPendingAdapterState);
|
||||
}*/
|
||||
mPendingAdapterState = nullptr;
|
||||
}
|
||||
// Now we have an adapter, we can clamp the pending current item and set it
|
||||
mCurrentItem = std::max(0, std::min(mPendingCurrentItem, adapter->getItemCount() - 1));
|
||||
mPendingCurrentItem = RecyclerView::NO_POSITION;
|
||||
mRecyclerView->scrollToPosition(mCurrentItem);
|
||||
//mAccessibilityProvider.onRestorePendingState();
|
||||
}
|
||||
#if 0
|
||||
void ViewPager2::dispatchRestoreInstanceState(SparseArray<Parcelable*>& container) {
|
||||
// RecyclerView changed an id, so we need to reflect that in the saved state
|
||||
Parcelable* state = container.get(getId());
|
||||
if (dynamic_cast<SavedState*>(state)) {
|
||||
const int previousRvId = ((SavedState*) state)->mRecyclerViewId;
|
||||
const int currentRvId = mRecyclerView->getId();
|
||||
container.put(currentRvId, container.get(previousRvId));
|
||||
container.remove(previousRvId);
|
||||
}
|
||||
|
||||
ViewGroup::dispatchRestoreInstanceState(container);
|
||||
|
||||
// State of ViewPager2 and its child (RecyclerView) has been restored now
|
||||
restorePendingState();
|
||||
}
|
||||
|
||||
ViewPager2::SavedState::SavedState(Parcel& source) {
|
||||
//super(source);
|
||||
//readValues(source, nullptr);
|
||||
}
|
||||
|
||||
ViewPager2::SavedState::SavedState(Parcelable superState) {
|
||||
//super(superState);
|
||||
}
|
||||
|
||||
/*void ViewPager2::SavedState::readValues(Parcel& source, ClassLoader loader) {
|
||||
mRecyclerViewId = source.readInt();
|
||||
mCurrentItem = source.readInt();
|
||||
mAdapterState = source.readParcelable(loader);
|
||||
}*/
|
||||
|
||||
void ViewPager2::SavedState::writeToParcel(Parcel& out, int flags) {
|
||||
//ViewGroup::writeToParcel(out, flags);
|
||||
out.writeInt(mRecyclerViewId);
|
||||
out.writeInt(mCurrentItem);
|
||||
out.writeParcelable(mAdapterState, flags);
|
||||
}
|
||||
#endif
|
||||
void ViewPager2::setAdapter(RecyclerView::Adapter* adapter) {
|
||||
RecyclerView::Adapter*currentAdapter = mRecyclerView->getAdapter();
|
||||
//mAccessibilityProvider.onDetachAdapter(currentAdapter);
|
||||
unregisterCurrentItemDataSetTracker(currentAdapter);
|
||||
mRecyclerView->setAdapter(adapter);
|
||||
mCurrentItem = 0;
|
||||
restorePendingState();
|
||||
//mAccessibilityProvider->onAttachAdapter(adapter);
|
||||
registerCurrentItemDataSetTracker(adapter);
|
||||
}
|
||||
|
||||
void ViewPager2::registerCurrentItemDataSetTracker(RecyclerView::Adapter*adapter) {
|
||||
if (adapter != nullptr) {
|
||||
adapter->registerAdapterDataObserver(mCurrentItemDataSetChangeObserver);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewPager2::unregisterCurrentItemDataSetTracker(RecyclerView::Adapter*adapter) {
|
||||
if (adapter != nullptr) {
|
||||
adapter->unregisterAdapterDataObserver(mCurrentItemDataSetChangeObserver);
|
||||
}
|
||||
}
|
||||
|
||||
RecyclerView::Adapter* ViewPager2::getAdapter() {
|
||||
return mRecyclerView->getAdapter();
|
||||
}
|
||||
|
||||
void ViewPager2::onViewAdded(View* child) {
|
||||
// TODO(b/70666620): consider adding a support for Decor views
|
||||
FATAL(" does not support direct child views");
|
||||
}
|
||||
|
||||
void ViewPager2::onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
measureChild(mRecyclerView, widthMeasureSpec, heightMeasureSpec);
|
||||
int width = mRecyclerView->getMeasuredWidth();
|
||||
int height = mRecyclerView->getMeasuredHeight();
|
||||
int childState = mRecyclerView->getMeasuredState();
|
||||
|
||||
width += getPaddingLeft() + getPaddingRight();
|
||||
height += getPaddingTop() + getPaddingBottom();
|
||||
|
||||
width = std::max(width, getSuggestedMinimumWidth());
|
||||
height = std::max(height, getSuggestedMinimumHeight());
|
||||
|
||||
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
|
||||
resolveSizeAndState(height, heightMeasureSpec,
|
||||
childState << MEASURED_HEIGHT_STATE_SHIFT));
|
||||
}
|
||||
|
||||
void ViewPager2::onLayout(bool changed, int l, int t, int w, int h) {
|
||||
int width = mRecyclerView->getMeasuredWidth();
|
||||
int height = mRecyclerView->getMeasuredHeight();
|
||||
|
||||
// TODO(b/70666626): consider delegating padding handling to the RecyclerView to avoid
|
||||
// an unnatural page transition effect: http://shortn/_Vnug3yZpQT
|
||||
mTmpContainerRect.left = getPaddingLeft();
|
||||
mTmpContainerRect.width =w - getPaddingLeft() - getPaddingRight();
|
||||
mTmpContainerRect.top = getPaddingTop();
|
||||
mTmpContainerRect.height = h - getPaddingTop() - getPaddingBottom();
|
||||
|
||||
Gravity::apply(Gravity::TOP | Gravity::START, width, height, mTmpContainerRect, mTmpChildRect);
|
||||
mRecyclerView->layout(mTmpChildRect.left, mTmpChildRect.top, mTmpChildRect.width,
|
||||
mTmpChildRect.height);
|
||||
|
||||
if (mCurrentItemDirty) {
|
||||
updateCurrentItem();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewPager2::updateCurrentItem() {
|
||||
if (mPagerSnapHelper == nullptr) {
|
||||
FATAL("Design assumption violated.");
|
||||
}
|
||||
|
||||
View* snapView = mPagerSnapHelper->findSnapView(*mLayoutManager);
|
||||
if (snapView == nullptr) {
|
||||
return; // nothing we can do
|
||||
}
|
||||
const int snapPosition = mLayoutManager->getPosition(snapView);
|
||||
|
||||
if (snapPosition != mCurrentItem && getScrollState() == SCROLL_STATE_IDLE) {
|
||||
/** TODO: revisit if push to {@link ScrollEventAdapter} / separate component */
|
||||
mPageChangeEventDispatcher->onPageSelected(snapPosition);
|
||||
}
|
||||
|
||||
mCurrentItemDirty = false;
|
||||
}
|
||||
|
||||
int ViewPager2::getPageSize() {
|
||||
RecyclerView* rv = mRecyclerView;
|
||||
return getOrientation() == ORIENTATION_HORIZONTAL
|
||||
? rv->getWidth() - rv->getPaddingLeft() - rv->getPaddingRight()
|
||||
: rv->getHeight() - rv->getPaddingTop() - rv->getPaddingBottom();
|
||||
}
|
||||
|
||||
void ViewPager2::setOrientation(int orientation) {
|
||||
mLayoutManager->setOrientation(orientation);
|
||||
//mAccessibilityProvider.onSetOrientation();
|
||||
}
|
||||
|
||||
int ViewPager2::getOrientation() {
|
||||
return mLayoutManager->getOrientation();
|
||||
}
|
||||
|
||||
bool ViewPager2::isRtl() {
|
||||
return mLayoutManager->getLayoutDirection() == View::LAYOUT_DIRECTION_RTL;
|
||||
}
|
||||
|
||||
|
||||
void ViewPager2::setCurrentItem(int item) {
|
||||
setCurrentItem(item, true);
|
||||
}
|
||||
|
||||
void ViewPager2::setCurrentItem(int item, bool smoothScroll) {
|
||||
if (isFakeDragging()) {
|
||||
FATAL("Cannot change current item when ViewPager2 is fake dragging");
|
||||
}
|
||||
setCurrentItemInternal(item, smoothScroll);
|
||||
}
|
||||
|
||||
void ViewPager2::setCurrentItemInternal(int item, bool smoothScroll) {
|
||||
|
||||
// 1. Preprocessing (check state, validate item, decide if update is necessary, etc)
|
||||
|
||||
RecyclerView::Adapter* adapter = getAdapter();
|
||||
if (adapter == nullptr) {
|
||||
// Update the pending current item if we're still waiting for the adapter
|
||||
if (mPendingCurrentItem != RecyclerView::NO_POSITION) {
|
||||
mPendingCurrentItem = std::max(item, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (adapter->getItemCount() <= 0) {
|
||||
// Adapter is empty
|
||||
return;
|
||||
}
|
||||
item = std::max(item, 0);
|
||||
item = std::min(item, adapter->getItemCount() - 1);
|
||||
|
||||
if (item == mCurrentItem && mScrollEventAdapter->isIdle()) {
|
||||
// Already at the correct page
|
||||
return;
|
||||
}
|
||||
if (item == mCurrentItem && smoothScroll) {
|
||||
// Already scrolling to the correct page, but not yet there. Only handle instant scrolls
|
||||
// because then we need to interrupt the current smooth scroll.
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Update the item internally
|
||||
|
||||
double previousItem = mCurrentItem;
|
||||
mCurrentItem = item;
|
||||
//mAccessibilityProvider->onSetNewCurrentItem();
|
||||
|
||||
if (!mScrollEventAdapter->isIdle()) {
|
||||
// Scroll in progress, overwrite previousItem with actual current position
|
||||
previousItem = mScrollEventAdapter->getRelativeScrollPosition();
|
||||
}
|
||||
|
||||
// 3. Perform the necessary scroll actions on RecyclerView
|
||||
|
||||
mScrollEventAdapter->notifyProgrammaticScroll(item, smoothScroll);
|
||||
if (!smoothScroll) {
|
||||
mRecyclerView->scrollToPosition(item);
|
||||
return;
|
||||
}
|
||||
|
||||
// For smooth scroll, pre-jump to nearby item for long jumps.
|
||||
if (std::abs(item - previousItem) > 3) {
|
||||
mRecyclerView->scrollToPosition(item > previousItem ? item - 3 : item + 3);
|
||||
// TODO(b/114361680): call smoothScrollToPosition synchronously (blocked by b/114019007)
|
||||
Runnable run([this,item](){
|
||||
mRecyclerView->smoothScrollToPosition(item);
|
||||
});
|
||||
mRecyclerView->post(run);//new SmoothScrollToPosition(item, mRecyclerView));
|
||||
} else {
|
||||
mRecyclerView->smoothScrollToPosition(item);
|
||||
}
|
||||
}
|
||||
|
||||
int ViewPager2::getCurrentItem() const{
|
||||
return mCurrentItem;
|
||||
}
|
||||
|
||||
int ViewPager2::getScrollState() {
|
||||
return mScrollEventAdapter->getScrollState();
|
||||
}
|
||||
|
||||
bool ViewPager2::beginFakeDrag() {
|
||||
return mFakeDragger->beginFakeDrag();
|
||||
}
|
||||
|
||||
|
||||
bool ViewPager2::fakeDragBy(float offsetPxFloat) {
|
||||
return mFakeDragger->fakeDragBy(offsetPxFloat);
|
||||
}
|
||||
|
||||
bool ViewPager2::endFakeDrag() {
|
||||
return mFakeDragger->endFakeDrag();
|
||||
}
|
||||
|
||||
bool ViewPager2::isFakeDragging() {
|
||||
return mFakeDragger->isFakeDragging();
|
||||
}
|
||||
|
||||
void ViewPager2::snapToPage() {
|
||||
// Method copied from PagerSnapHelper#snapToTargetExistingView
|
||||
// When fixing something here, make sure to update that method as well
|
||||
View* view = mPagerSnapHelper->findSnapView(*mLayoutManager);
|
||||
if (view == nullptr) {
|
||||
return;
|
||||
}
|
||||
int snapDistance[2];
|
||||
mPagerSnapHelper->calculateDistanceToFinalSnap(*mLayoutManager,*view,snapDistance);
|
||||
//noinspection ConstantConditions
|
||||
if (snapDistance[0] != 0 || snapDistance[1] != 0) {
|
||||
mRecyclerView->smoothScrollBy(snapDistance[0], snapDistance[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewPager2::setUserInputEnabled(bool enabled) {
|
||||
mUserInputEnabled = enabled;
|
||||
//mAccessibilityProvider.onSetUserInputEnabled();
|
||||
}
|
||||
|
||||
bool ViewPager2::isUserInputEnabled() {
|
||||
return mUserInputEnabled;
|
||||
}
|
||||
|
||||
void ViewPager2::setOffscreenPageLimit(int limit) {
|
||||
if (limit < 1 && limit != OFFSCREEN_PAGE_LIMIT_DEFAULT) {
|
||||
FATAL("Offscreen page limit must be OFFSCREEN_PAGE_LIMIT_DEFAULT or a number > 0");
|
||||
}
|
||||
mOffscreenPageLimit = limit;
|
||||
// Trigger layout so prefetch happens through getExtraLayoutSize()
|
||||
mRecyclerView->requestLayout();
|
||||
}
|
||||
|
||||
int ViewPager2::getOffscreenPageLimit()const{
|
||||
return mOffscreenPageLimit;
|
||||
}
|
||||
|
||||
bool ViewPager2::canScrollHorizontally(int direction)const{
|
||||
return mRecyclerView->canScrollHorizontally(direction);
|
||||
}
|
||||
|
||||
bool ViewPager2::canScrollVertically(int direction)const{
|
||||
return mRecyclerView->canScrollVertically(direction);
|
||||
}
|
||||
|
||||
void ViewPager2::registerOnPageChangeCallback(OnPageChangeCallback callback) {
|
||||
mExternalPageChangeCallbacks->addOnPageChangeCallback(callback);
|
||||
}
|
||||
|
||||
void ViewPager2::unregisterOnPageChangeCallback(OnPageChangeCallback callback) {
|
||||
mExternalPageChangeCallbacks->removeOnPageChangeCallback(callback);
|
||||
}
|
||||
|
||||
void ViewPager2::setPageTransformer(PageTransformer* transformer) {
|
||||
if (transformer != nullptr) {
|
||||
if (!mSavedItemAnimatorPresent) {
|
||||
mSavedItemAnimator = mRecyclerView->getItemAnimator();
|
||||
mSavedItemAnimatorPresent = true;
|
||||
}
|
||||
mRecyclerView->setItemAnimator(nullptr);
|
||||
} else {
|
||||
if (mSavedItemAnimatorPresent) {
|
||||
mRecyclerView->setItemAnimator(mSavedItemAnimator);
|
||||
mSavedItemAnimator = nullptr;
|
||||
mSavedItemAnimatorPresent = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add support for reverseDrawingOrder: b/112892792
|
||||
// TODO: add support for pageLayerType: b/112893074
|
||||
if (transformer == mPageTransformerAdapter->getPageTransformer()) {
|
||||
return;
|
||||
}
|
||||
mPageTransformerAdapter->setPageTransformer(transformer);
|
||||
requestTransform();
|
||||
}
|
||||
|
||||
void ViewPager2::requestTransform() {
|
||||
if (mPageTransformerAdapter->getPageTransformer() == nullptr) {
|
||||
return;
|
||||
}
|
||||
double relativePosition = mScrollEventAdapter->getRelativeScrollPosition();
|
||||
int position = (int) relativePosition;
|
||||
float positionOffset = (float) (relativePosition - position);
|
||||
int positionOffsetPx = std::round(getPageSize() * positionOffset);
|
||||
mPageTransformerAdapter->onPageScrolled(position, positionOffset, positionOffsetPx);
|
||||
}
|
||||
|
||||
View& ViewPager2::setLayoutDirection(int layoutDirection) {
|
||||
ViewGroup::setLayoutDirection(layoutDirection);
|
||||
//mAccessibilityProvider.onSetLayoutDirection();
|
||||
return *this;
|
||||
}
|
||||
#if 0
|
||||
void ViewPager2::onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
mAccessibilityProvider.onInitializeAccessibilityNodeInfo(info);
|
||||
}
|
||||
|
||||
bool ViewPager2::performAccessibilityAction(int action, Bundle arguments) {
|
||||
if (mAccessibilityProvider.handlesPerformAccessibilityAction(action, arguments)) {
|
||||
return mAccessibilityProvider.onPerformAccessibilityAction(action, arguments);
|
||||
}
|
||||
return super.performAccessibilityAction(action, arguments);
|
||||
}
|
||||
#endif
|
||||
ViewPager2::RecyclerViewImpl::RecyclerViewImpl(Context* context,const AttributeSet&attr)
|
||||
:RecyclerView(context,attr){
|
||||
}
|
||||
#if 0
|
||||
CharSequence ViewPager2::RecyclerViewImpl::getAccessibilityClassName() {
|
||||
if (mAccessibilityProvider.handlesRvGetAccessibilityClassName()) {
|
||||
return mAccessibilityProvider.onRvGetAccessibilityClassName();
|
||||
}
|
||||
return super.getAccessibilityClassName();
|
||||
}
|
||||
|
||||
void ViewPager2::RecyclerViewImpl::onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) {
|
||||
super.onInitializeAccessibilityEvent(event);
|
||||
event.setFromIndex(mCurrentItem);
|
||||
event.setToIndex(mCurrentItem);
|
||||
mAccessibilityProvider.onRvInitializeAccessibilityEvent(event);
|
||||
}
|
||||
#endif
|
||||
bool ViewPager2::RecyclerViewImpl::onTouchEvent(MotionEvent& event) {
|
||||
return mVP->isUserInputEnabled() && RecyclerView::onTouchEvent(event);
|
||||
}
|
||||
|
||||
bool ViewPager2::RecyclerViewImpl::onInterceptTouchEvent(MotionEvent& ev) {
|
||||
return mVP->isUserInputEnabled() && RecyclerView::onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
ViewPager2::LinearLayoutManagerImpl::LinearLayoutManagerImpl(Context* context,ViewPager2*vp)
|
||||
:LinearLayoutManager(context){
|
||||
mVP = vp;
|
||||
}
|
||||
#if 0
|
||||
bool ViewPager2::LinearLayoutManagerImpl::performAccessibilityAction(@NonNull RecyclerView::Recycler recycler,
|
||||
@NonNull RecyclerView::State state, int action, @Nullable Bundle args) {
|
||||
if (mAccessibilityProvider.handlesLmPerformAccessibilityAction(action)) {
|
||||
return mAccessibilityProvider.onLmPerformAccessibilityAction(action);
|
||||
}
|
||||
return super.performAccessibilityAction(recycler, state, action, args);
|
||||
}
|
||||
|
||||
void ViewPager2::LinearLayoutManagerImpl::onInitializeAccessibilityNodeInfo(@NonNull RecyclerView::Recycler recycler,
|
||||
@NonNull RecyclerView::State state, @NonNull AccessibilityNodeInfoCompat info) {
|
||||
super.onInitializeAccessibilityNodeInfo(recycler, state, info);
|
||||
mAccessibilityProvider.onLmInitializeAccessibilityNodeInfo(info);
|
||||
}
|
||||
#endif
|
||||
void ViewPager2::LinearLayoutManagerImpl::calculateExtraLayoutSpace(RecyclerView::State& state,
|
||||
int extraLayoutSpace[2]) {
|
||||
const int pageLimit = mVP->getOffscreenPageLimit();
|
||||
if (pageLimit == OFFSCREEN_PAGE_LIMIT_DEFAULT) {
|
||||
// Only do custom prefetching of offscreen pages if requested
|
||||
LinearLayoutManager::calculateExtraLayoutSpace(state, extraLayoutSpace);
|
||||
return;
|
||||
}
|
||||
const int offscreenSpace = mVP->getPageSize() * pageLimit;
|
||||
extraLayoutSpace[0] = offscreenSpace;
|
||||
extraLayoutSpace[1] = offscreenSpace;
|
||||
}
|
||||
|
||||
bool ViewPager2::LinearLayoutManagerImpl::requestChildRectangleOnScreen(RecyclerView& parent,
|
||||
View& child,const Rect& rect, bool immediate, bool focusedChildVisible) {
|
||||
return false; // users should use setCurrentItem instead
|
||||
}
|
||||
|
||||
ViewPager2::PagerSnapHelperImpl::PagerSnapHelperImpl():PagerSnapHelper(){
|
||||
}
|
||||
View* ViewPager2::PagerSnapHelperImpl::findSnapView(RecyclerView::LayoutManager& layoutManager) {
|
||||
// When interrupting a smooth scroll with a fake drag, we stop RecyclerView's scroll
|
||||
// animation, which fires a scroll state change to IDLE. PagerSnapHelper then kicks in
|
||||
// to snap to a page, which we need to prevent here.
|
||||
// Simplifying that case: during a fake drag, no snapping should occur.
|
||||
ViewPager2*vp = dynamic_cast<ViewPager2*>(mRecyclerView->getParent());
|
||||
return vp->isFakeDragging() ? nullptr : PagerSnapHelper::findSnapView(layoutManager);
|
||||
}
|
||||
|
||||
|
||||
void ViewPager2::addItemDecoration(RecyclerView::ItemDecoration* decor) {
|
||||
mRecyclerView->addItemDecoration(decor);
|
||||
}
|
||||
|
||||
void ViewPager2::addItemDecoration(RecyclerView::ItemDecoration* decor, int index) {
|
||||
mRecyclerView->addItemDecoration(decor, index);
|
||||
}
|
||||
|
||||
RecyclerView::ItemDecoration* ViewPager2::getItemDecorationAt(int index) {
|
||||
return mRecyclerView->getItemDecorationAt(index);
|
||||
}
|
||||
|
||||
int ViewPager2::getItemDecorationCount() {
|
||||
return mRecyclerView->getItemDecorationCount();
|
||||
}
|
||||
|
||||
void ViewPager2::invalidateItemDecorations() {
|
||||
mRecyclerView->invalidateItemDecorations();
|
||||
}
|
||||
|
||||
void ViewPager2::removeItemDecorationAt(int index) {
|
||||
mRecyclerView->removeItemDecorationAt(index);
|
||||
}
|
||||
|
||||
void ViewPager2::removeItemDecoration(RecyclerView::ItemDecoration* decor) {
|
||||
mRecyclerView->removeItemDecoration(decor);
|
||||
}
|
||||
#if 0
|
||||
// TODO(b/141956012): Suppressed during upgrade to AGP 3.6.
|
||||
class BasicAccessibilityProvider extends AccessibilityProvider {
|
||||
@Override
|
||||
public bool handlesLmPerformAccessibilityAction(int action) {
|
||||
return (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD
|
||||
|| action == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD)
|
||||
&& !isUserInputEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public bool onLmPerformAccessibilityAction(int action) {
|
||||
if (!handlesLmPerformAccessibilityAction(action)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLmInitializeAccessibilityNodeInfo(
|
||||
@NonNull AccessibilityNodeInfoCompat info) {
|
||||
if (!isUserInputEnabled()) {
|
||||
info.removeAction(AccessibilityActionCompat.ACTION_SCROLL_BACKWARD);
|
||||
info.removeAction(AccessibilityActionCompat.ACTION_SCROLL_FORWARD);
|
||||
info.setScrollable(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public bool handlesRvGetAccessibilityClassName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence onRvGetAccessibilityClassName() {
|
||||
if (!handlesRvGetAccessibilityClassName()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return "androidx.viewpager.widget.ViewPager";
|
||||
}
|
||||
}
|
||||
|
||||
class PageAwareAccessibilityProvider extends AccessibilityProvider {
|
||||
private final AccessibilityViewCommand mActionPageForward =
|
||||
new AccessibilityViewCommand() {
|
||||
@Override
|
||||
public bool perform(@NonNull View view,
|
||||
@Nullable CommandArguments arguments) {
|
||||
ViewPager2 viewPager = (ViewPager2) view;
|
||||
setCurrentItemFromAccessibilityCommand(viewPager.getCurrentItem() + 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private final AccessibilityViewCommand mActionPageBackward =
|
||||
new AccessibilityViewCommand() {
|
||||
@Override
|
||||
public bool perform(@NonNull View view,
|
||||
@Nullable CommandArguments arguments) {
|
||||
ViewPager2 viewPager = (ViewPager2) view;
|
||||
setCurrentItemFromAccessibilityCommand(viewPager.getCurrentItem() - 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private RecyclerView::AdapterDataObserver mAdapterDataObserver;
|
||||
|
||||
@Override
|
||||
public void onInitialize(@NonNull CompositeOnPageChangeCallback pageChangeEventDispatcher,
|
||||
@NonNull RecyclerView recyclerView) {
|
||||
ViewCompat.setImportantForAccessibility(recyclerView,
|
||||
ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
|
||||
mAdapterDataObserver = new DataSetChangeObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
updatePageAccessibilityActions();
|
||||
}
|
||||
};
|
||||
|
||||
if (ViewCompat.getImportantForAccessibility(ViewPager2.this)
|
||||
== ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
|
||||
ViewCompat.setImportantForAccessibility(ViewPager2.this,
|
||||
ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public bool handlesGetAccessibilityClassName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onGetAccessibilityClassName() {
|
||||
if (!handlesGetAccessibilityClassName()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return "androidx.viewpager.widget.ViewPager";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestorePendingState() {
|
||||
updatePageAccessibilityActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachAdapter(@Nullable Adapter<?> newAdapter) {
|
||||
updatePageAccessibilityActions();
|
||||
if (newAdapter != null) {
|
||||
newAdapter.registerAdapterDataObserver(mAdapterDataObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachAdapter(@Nullable Adapter<?> oldAdapter) {
|
||||
if (oldAdapter != null) {
|
||||
oldAdapter.unregisterAdapterDataObserver(mAdapterDataObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetOrientation() {
|
||||
updatePageAccessibilityActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetNewCurrentItem() {
|
||||
updatePageAccessibilityActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetUserInputEnabled() {
|
||||
updatePageAccessibilityActions();
|
||||
if (Build.VERSION.SDK_INT < 21) {
|
||||
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetLayoutDirection() {
|
||||
updatePageAccessibilityActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
addCollectionInfo(info);
|
||||
if (Build.VERSION.SDK_INT >= 16) {
|
||||
addScrollActions(info);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public bool handlesPerformAccessibilityAction(int action, Bundle arguments) {
|
||||
return action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD
|
||||
|| action == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public bool onPerformAccessibilityAction(int action, Bundle arguments) {
|
||||
if (!handlesPerformAccessibilityAction(action, arguments)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
int nextItem = (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD)
|
||||
? getCurrentItem() - 1
|
||||
: getCurrentItem() + 1;
|
||||
setCurrentItemFromAccessibilityCommand(nextItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRvInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) {
|
||||
event.setSource(ViewPager2.this);
|
||||
event.setClassName(onGetAccessibilityClassName());
|
||||
}
|
||||
|
||||
void setCurrentItemFromAccessibilityCommand(int item) {
|
||||
if (isUserInputEnabled()) {
|
||||
setCurrentItemInternal(item, true);
|
||||
}
|
||||
}
|
||||
|
||||
void updatePageAccessibilityActions() {
|
||||
ViewPager2 viewPager = ViewPager2.this;
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
final int actionIdPageLeft = android.R.id.accessibilityActionPageLeft;
|
||||
@SuppressLint("InlinedApi")
|
||||
final int actionIdPageRight = android.R.id.accessibilityActionPageRight;
|
||||
@SuppressLint("InlinedApi")
|
||||
final int actionIdPageUp = android.R.id.accessibilityActionPageUp;
|
||||
@SuppressLint("InlinedApi")
|
||||
final int actionIdPageDown = android.R.id.accessibilityActionPageDown;
|
||||
|
||||
ViewCompat.removeAccessibilityAction(viewPager, actionIdPageLeft);
|
||||
ViewCompat.removeAccessibilityAction(viewPager, actionIdPageRight);
|
||||
ViewCompat.removeAccessibilityAction(viewPager, actionIdPageUp);
|
||||
ViewCompat.removeAccessibilityAction(viewPager, actionIdPageDown);
|
||||
|
||||
if (getAdapter() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int itemCount = getAdapter().getItemCount();
|
||||
if (itemCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isUserInputEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getOrientation() == ORIENTATION_HORIZONTAL) {
|
||||
bool isLayoutRtl = isRtl();
|
||||
int actionIdPageForward = isLayoutRtl ? actionIdPageLeft : actionIdPageRight;
|
||||
int actionIdPageBackward = isLayoutRtl ? actionIdPageRight : actionIdPageLeft;
|
||||
|
||||
if (mCurrentItem < itemCount - 1) {
|
||||
ViewCompat.replaceAccessibilityAction(viewPager,
|
||||
new AccessibilityActionCompat(actionIdPageForward, null), null,
|
||||
mActionPageForward);
|
||||
}
|
||||
if (mCurrentItem > 0) {
|
||||
ViewCompat.replaceAccessibilityAction(viewPager,
|
||||
new AccessibilityActionCompat(actionIdPageBackward, null), null,
|
||||
mActionPageBackward);
|
||||
}
|
||||
} else {
|
||||
if (mCurrentItem < itemCount - 1) {
|
||||
ViewCompat.replaceAccessibilityAction(viewPager,
|
||||
new AccessibilityActionCompat(actionIdPageDown, null), null,
|
||||
mActionPageForward);
|
||||
}
|
||||
if (mCurrentItem > 0) {
|
||||
ViewCompat.replaceAccessibilityAction(viewPager,
|
||||
new AccessibilityActionCompat(actionIdPageUp, null), null,
|
||||
mActionPageBackward);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addCollectionInfo(AccessibilityNodeInfo info) {
|
||||
int rowCount = 0;
|
||||
int colCount = 0;
|
||||
if (getAdapter() != null) {
|
||||
if (getOrientation() == ORIENTATION_VERTICAL) {
|
||||
rowCount = getAdapter().getItemCount();
|
||||
} else {
|
||||
colCount = getAdapter().getItemCount();
|
||||
}
|
||||
}
|
||||
AccessibilityNodeInfoCompat nodeInfoCompat = AccessibilityNodeInfoCompat.wrap(info);
|
||||
AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo =
|
||||
AccessibilityNodeInfoCompat.CollectionInfoCompat.obtain(rowCount, colCount,
|
||||
/* hierarchical= */false,
|
||||
AccessibilityNodeInfoCompat.CollectionInfoCompat.SELECTION_MODE_NONE);
|
||||
nodeInfoCompat.setCollectionInfo(collectionInfo);
|
||||
}
|
||||
|
||||
private void addScrollActions(AccessibilityNodeInfo info) {
|
||||
final Adapter<?> adapter = getAdapter();
|
||||
if (adapter == null) {
|
||||
return;
|
||||
}
|
||||
int itemCount = adapter.getItemCount();
|
||||
if (itemCount == 0 || !isUserInputEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (mCurrentItem > 0) {
|
||||
info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
|
||||
}
|
||||
if (mCurrentItem < itemCount - 1) {
|
||||
info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
|
||||
}
|
||||
info.setScrollable(true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}/*endof namespace*/
|
||||
|
279
src/gui/widgetEx/viewpager2.h
Executable file
279
src/gui/widgetEx/viewpager2.h
Executable file
@ -0,0 +1,279 @@
|
||||
#ifndef __VIEWPAGER2_H__
|
||||
#define __VIEWPAGER2_H__
|
||||
#include <widgetEx/recyclerview/recyclerview.h>
|
||||
#include <widgetEx/recyclerview/linearlayoutmanager.h>
|
||||
#include <widgetEx/recyclerview/pagersnaphelper.h>
|
||||
namespace cdroid{
|
||||
class PagerSnapHelper;
|
||||
class FakeDrag;
|
||||
class ScrollEventAdapter;
|
||||
class CompositeOnPageChangeCallback;
|
||||
class PageTransformerAdapter;
|
||||
class ViewPager2:public ViewGroup {
|
||||
public:
|
||||
class PageTransformer {
|
||||
public:
|
||||
virtual void transformPage(View& var1, float var2)=0;
|
||||
};
|
||||
class OnPageChangeCallback:public EventSet{
|
||||
public:
|
||||
CallbackBase<void,int,float,int> onPageScrolled;//(int position, float positionOffset, int positionOffsetPixels);
|
||||
CallbackBase<void,int>onPageSelected;//(int position);
|
||||
CallbackBase<void,int>onPageScrollStateChanged;//(int state);
|
||||
};
|
||||
protected:
|
||||
/** Feature flag while stabilizing enhanced a11y */
|
||||
static constexpr bool sFeatureEnhancedA11yEnabled = true;
|
||||
public:
|
||||
static constexpr int ORIENTATION_HORIZONTAL = RecyclerView::HORIZONTAL;
|
||||
static constexpr int ORIENTATION_VERTICAL = RecyclerView::VERTICAL;
|
||||
static constexpr int SCROLL_STATE_IDLE = 0;
|
||||
static constexpr int SCROLL_STATE_DRAGGING = 1;
|
||||
static constexpr int SCROLL_STATE_SETTLING = 2;
|
||||
static constexpr int OFFSCREEN_PAGE_LIMIT_DEFAULT = -1;
|
||||
private:
|
||||
class RecyclerViewImpl;
|
||||
class LinearLayoutManagerImpl;
|
||||
class RecyclerViewImpl;
|
||||
class PagerSnapHelperImpl;
|
||||
RecyclerView::AdapterDataObserver* mCurrentItemDataSetChangeObserver;
|
||||
// reused in layout(...)
|
||||
Rect mTmpContainerRect;
|
||||
Rect mTmpChildRect;
|
||||
Runnable mSmoothScrollToPositionRunnable;
|
||||
CompositeOnPageChangeCallback* mExternalPageChangeCallbacks;
|
||||
LinearLayoutManager* mLayoutManager;
|
||||
int mPendingCurrentItem = RecyclerView::NO_POSITION;
|
||||
Parcelable* mPendingAdapterState;
|
||||
PagerSnapHelper* mPagerSnapHelper;
|
||||
CompositeOnPageChangeCallback* mPageChangeEventDispatcher;
|
||||
FakeDrag* mFakeDragger;
|
||||
PageTransformerAdapter* mPageTransformerAdapter;
|
||||
RecyclerView::ItemAnimator* mSavedItemAnimator = nullptr;
|
||||
bool mSavedItemAnimatorPresent = false;
|
||||
bool mUserInputEnabled = true;
|
||||
int mOffscreenPageLimit = OFFSCREEN_PAGE_LIMIT_DEFAULT;
|
||||
protected:
|
||||
int mCurrentItem;
|
||||
bool mCurrentItemDirty = false;
|
||||
RecyclerViewImpl* mRecyclerView;
|
||||
ScrollEventAdapter* mScrollEventAdapter;
|
||||
//AccessibilityProvider* mAccessibilityProvider; // to avoid creation of a synthetic accessor
|
||||
private:
|
||||
class RecyclerViewImpl;
|
||||
void initialize(Context* context, const AttributeSet& attrs);
|
||||
//RecyclerView::OnChildAttachStateChangeListener enforceChildFillListener();
|
||||
void setOrientation(Context* context,const AttributeSet& attrs);
|
||||
void restorePendingState();
|
||||
void unregisterCurrentItemDataSetTracker(RecyclerView::Adapter*adapter);
|
||||
protected:
|
||||
friend class FakeDrag;
|
||||
friend class ScrollEventAdapter;
|
||||
//Parcelable* onSaveInstanceState()override;
|
||||
//void onRestoreInstanceState(Parcelable& state)override;
|
||||
//void dispatchRestoreInstanceState(SparseArray<Parcelable*>& container)override;
|
||||
void onMeasure(int widthMeasureSpec, int heightMeasureSpec)override;
|
||||
void onLayout(bool changed, int l, int t, int w, int h)override;
|
||||
|
||||
void onViewAdded(View* child)override;
|
||||
void updateCurrentItem();
|
||||
int getPageSize();
|
||||
void setCurrentItemInternal(int item, bool smoothScroll);
|
||||
void snapToPage();
|
||||
public:
|
||||
ViewPager2(Context* context, const AttributeSet& attrs);
|
||||
//CharSequence getAccessibilityClassName()override;
|
||||
|
||||
void setAdapter(RecyclerView::Adapter* adapter);
|
||||
void registerCurrentItemDataSetTracker(RecyclerView::Adapter* adapter);
|
||||
RecyclerView::Adapter* getAdapter();
|
||||
void setOrientation(int orientation);
|
||||
int getOrientation();
|
||||
bool isRtl();
|
||||
void setCurrentItem(int item);
|
||||
void setCurrentItem(int item, bool smoothScroll);
|
||||
int getCurrentItem()const;
|
||||
int getScrollState();
|
||||
bool beginFakeDrag();
|
||||
bool fakeDragBy(float offsetPxFloat);
|
||||
bool endFakeDrag();
|
||||
bool isFakeDragging();
|
||||
void setUserInputEnabled(bool enabled);
|
||||
|
||||
bool isUserInputEnabled();
|
||||
|
||||
void setOffscreenPageLimit(int limit);
|
||||
int getOffscreenPageLimit()const;
|
||||
virtual bool canScrollHorizontally(int direction)const;
|
||||
virtual bool canScrollVertically(int direction)const;
|
||||
void registerOnPageChangeCallback(OnPageChangeCallback callback);
|
||||
void unregisterOnPageChangeCallback(OnPageChangeCallback callback);
|
||||
void setPageTransformer(PageTransformer* transformer);
|
||||
void requestTransform();
|
||||
View&setLayoutDirection(int layoutDirection)override;
|
||||
//void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info)override;
|
||||
bool performAccessibilityAction(int action, Bundle arguments);
|
||||
|
||||
#if 0
|
||||
#endif
|
||||
|
||||
void addItemDecoration(RecyclerView::ItemDecoration* decor);
|
||||
void addItemDecoration(RecyclerView::ItemDecoration* decor, int index);
|
||||
RecyclerView::ItemDecoration* getItemDecorationAt(int index);
|
||||
int getItemDecorationCount();
|
||||
void invalidateItemDecorations();
|
||||
void removeItemDecorationAt(int index);
|
||||
void removeItemDecoration(RecyclerView::ItemDecoration* decor);
|
||||
#if 0
|
||||
private class AccessibilityProvider {
|
||||
void onInitialize(@NonNull CompositeOnPageChangeCallback pageChangeEventDispatcher,RecyclerView recyclerView);
|
||||
virtual bool handlesGetAccessibilityClassName();
|
||||
virtual String onGetAccessibilityClassName() {
|
||||
virtual void onRestorePendingState(){}
|
||||
virtual void onAttachAdapter(@Nullable Adapter<?> newAdapter){}
|
||||
virtual void onDetachAdapter(@Nullable Adapter<?> oldAdapter){}
|
||||
virtual void onSetOrientation(){}
|
||||
virtual void onSetNewCurrentItem(){}
|
||||
virtual void onSetUserInputEnabled(){}
|
||||
virtual void onSetLayoutDirection(){}
|
||||
virtual void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { }
|
||||
virtual bool handlesPerformAccessibilityAction(int action, Bundle arguments) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool onPerformAccessibilityAction(int action, Bundle arguments) {
|
||||
throw new IllegalStateException("Not implemented.");
|
||||
}
|
||||
|
||||
virtual void onRvInitializeAccessibilityEvent(@NonNull AccessibilityEvent event){}
|
||||
|
||||
virtual bool handlesLmPerformAccessibilityAction(int action) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool onLmPerformAccessibilityAction(int action) {
|
||||
throw new IllegalStateException("Not implemented.");
|
||||
}
|
||||
|
||||
virtual void onLmInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfoCompat info) {
|
||||
}
|
||||
|
||||
virtual bool handlesRvGetAccessibilityClassName() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual CharSequence onRvGetAccessibilityClassName() {
|
||||
throw new IllegalStateException("Not implemented.");
|
||||
}
|
||||
};
|
||||
|
||||
class BasicAccessibilityProvider:public AccessibilityProvider {
|
||||
public:
|
||||
bool handlesLmPerformAccessibilityAction(int action)override;
|
||||
bool onLmPerformAccessibilityAction(int action)override
|
||||
void onLmInitializeAccessibilityNodeInfo(AccessibilityNodeInfoCompat info)override
|
||||
|
||||
bool handlesRvGetAccessibilityClassName()override
|
||||
CharSequence onRvGetAccessibilityClassName()override;
|
||||
};
|
||||
|
||||
class PageAwareAccessibilityProvider:public AccessibilityProvider {
|
||||
private:
|
||||
AccessibilityViewCommand mActionPageForward;
|
||||
AccessibilityViewCommand mActionPageBackward;
|
||||
RecyclerView::AdapterDataObserver mAdapterDataObserver;
|
||||
void addCollectionInfo(AccessibilityNodeInfo info);
|
||||
void addScrollActions(AccessibilityNodeInfo info);
|
||||
protected:
|
||||
void setCurrentItemFromAccessibilityCommand(int item);
|
||||
void updatePageAccessibilityActions();
|
||||
public:
|
||||
void onInitialize(@NonNull CompositeOnPageChangeCallback pageChangeEventDispatcher,
|
||||
@NonNull RecyclerView recyclerView)override;
|
||||
bool handlesGetAccessibilityClassName()override;
|
||||
String onGetAccessibilityClassName()override;
|
||||
void onRestorePendingState()override;
|
||||
void onAttachAdapter(@Nullable Adapter<?> newAdapter)override;
|
||||
void onDetachAdapter(@Nullable Adapter<?> oldAdapter)override;
|
||||
void onSetOrientation()override;
|
||||
void onSetNewCurrentItem()override;
|
||||
void onSetUserInputEnabled()override;
|
||||
void onSetLayoutDirection()override;
|
||||
void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info)override;
|
||||
bool handlesPerformAccessibilityAction(int action, Bundle arguments)override;
|
||||
bool onPerformAccessibilityAction(int action, Bundle arguments)override;
|
||||
void onRvInitializeAccessibilityEvent(@NonNull AccessibilityEvent event)override;
|
||||
};
|
||||
#endif
|
||||
};/*endof ViewPager2*/
|
||||
#if 0
|
||||
class ViewPager2::SavedState:public AbsSavedState{//BaseSavedState {
|
||||
protected:
|
||||
int mRecyclerViewId;
|
||||
int mCurrentItem;
|
||||
Parcelable* mAdapterState;
|
||||
friend ViewPager2;
|
||||
public:
|
||||
SavedState(Parcel& source);
|
||||
SavedState(Parcelable& superState);
|
||||
//void readValues(Parcel source, ClassLoader loader);//private
|
||||
void writeToParcel(Parcel& out, int flags);
|
||||
};
|
||||
#endif
|
||||
class ViewPager2::RecyclerViewImpl:public RecyclerView {
|
||||
private:
|
||||
friend ViewPager2;
|
||||
ViewPager2*mVP;
|
||||
public:
|
||||
RecyclerViewImpl(Context* context,const AttributeSet&);
|
||||
//CharSequence getAccessibilityClassName()override;
|
||||
//void onInitializeAccessibilityEvent(AccessibilityEvent event)override;
|
||||
bool onTouchEvent(MotionEvent& event)override;
|
||||
bool onInterceptTouchEvent(MotionEvent& ev)override;
|
||||
};
|
||||
|
||||
class ViewPager2::LinearLayoutManagerImpl:public LinearLayoutManager {
|
||||
protected:
|
||||
ViewPager2*mVP;
|
||||
protected:
|
||||
void calculateExtraLayoutSpace(RecyclerView::State& state,int extraLayoutSpace[2])override;
|
||||
public:
|
||||
LinearLayoutManagerImpl(Context* context,ViewPager2*vp);
|
||||
/*bool performAccessibilityAction(RecyclerView::Recycler& recycler,
|
||||
RecyclerView::State& state, int action, Bundle args)override;
|
||||
void onInitializeAccessibilityNodeInfo(RecyclerView::Recycler& recycler,
|
||||
RecyclerView::State& state, AccessibilityNodeInfo& info)override;*/
|
||||
bool requestChildRectangleOnScreen(RecyclerView& parent,View& child,const Rect& rect, bool immediate,bool focusedChildVisible)override;
|
||||
};
|
||||
|
||||
class ViewPager2::PagerSnapHelperImpl:public PagerSnapHelper {
|
||||
public:
|
||||
PagerSnapHelperImpl();
|
||||
View* findSnapView(RecyclerView::LayoutManager& layoutManager);
|
||||
};
|
||||
|
||||
class ViewPager2DataSetChangeObserver:public RecyclerView::AdapterDataObserver {
|
||||
public:
|
||||
virtual void onChanged()=0;
|
||||
|
||||
virtual void onItemRangeChanged(int positionStart, int itemCount)final{
|
||||
onChanged();
|
||||
}
|
||||
virtual void onItemRangeChanged(int positionStart, int itemCount,
|
||||
Object* payload)final{
|
||||
onChanged();
|
||||
}
|
||||
void onItemRangeInserted(int positionStart, int itemCount) {
|
||||
onChanged();
|
||||
}
|
||||
void onItemRangeRemoved(int positionStart, int itemCount)final{
|
||||
onChanged();
|
||||
}
|
||||
void onItemRangeMoved(int fromPosition, int toPosition, int itemCount)final{
|
||||
onChanged();
|
||||
}
|
||||
};
|
||||
|
||||
}/*endof namespace*/
|
||||
#endif/*__VIEWPAGER2_H__*/
|
||||
|
Loading…
Reference in New Issue
Block a user