【问题标题】:Quick Return on StaggeredGridViewStaggeredGridView 上的快速返回
【发布时间】:2014-12-03 01:03:30
【问题描述】:

我最近偶然发现了QuickReturn Library specified for Grid View

导入库工作正常,但在测试时我发现了以下错误。

为了可视化我的问题,我在 Youtube 上上传了 video。页脚的动画效果很好。但是当您滚动浏览该特定项目时,页脚会迅速出现并无缘无故地重新出现。

我猜这个问题是因为我在 Etsy 的 StaggeredGridView 上使用了为 GridView 指定的库。由于我不知道该库的哪个类对问题负责,因此我不发布任何代码。有什么需要调整的吗?

【问题讨论】:

    标签: android footer onscrolllistener staggered-gridview


    【解决方案1】:

    看看我是如何在下面的代码中解决这个问题的。这是一个自定义 OnScrollListener 用于 RecyclerViewGridLayoutManager

    您可以在此处查看更多示例:https://github.com/lawloretienne/QuickReturn

    QuickReturnFooterRecyclerViewFragment.java

    public class QuickReturnFooterRecyclerViewFragment extends Fragment {
    
        // region Member Variables
        private String[] mValues;
        private QuickReturnAnimationType mQuickReturnAnimationType;
        private String mLayoutManagerType;
    
        @InjectView(R.id.rv)
        RecyclerView mRecyclerView;
        @InjectView(R.id.quick_return_tv)
        TextView mQuickReturnTextView;
        // endregion
    
        // region Constructors
        public static QuickReturnFooterRecyclerViewFragment newInstance(Bundle extras) {
            QuickReturnFooterRecyclerViewFragment fragment = new QuickReturnFooterRecyclerViewFragment();
            fragment.setRetainInstance(true);
            fragment.setArguments(extras);
            return fragment;
        }
    
        public static QuickReturnFooterRecyclerViewFragment newInstance() {
            QuickReturnFooterRecyclerViewFragment fragment = new QuickReturnFooterRecyclerViewFragment();
            Bundle args = new Bundle();
            fragment.setArguments(args);
            return fragment;
        }
    
        public QuickReturnFooterRecyclerViewFragment() {
        }
        // endregion
    
        // region Lifecycle Methods
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            if(getArguments() != null) {
                mQuickReturnAnimationType = QuickReturnAnimationType.valueOf(getArguments().getString("quick_return_animation_type"));
                mLayoutManagerType = getArguments().getString("layout_manager");
            }
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_recyclerview_quick_return_footer, container, false);
            ButterKnife.inject(this, view);
            return view;
        }
    
        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            mValues = getResources().getStringArray(R.array.countries);
    
            if(mLayoutManagerType.equals("linear")){
                CountriesLinearLayoutAdapter countriesLinearLayoutAdapter = new CountriesLinearLayoutAdapter(getActivity(), Arrays.asList(mValues));
    
                RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
                mRecyclerView.setLayoutManager(layoutManager);
                mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
    
                mRecyclerView.setAdapter(countriesLinearLayoutAdapter);
            } else if(mLayoutManagerType.equals("grid")) {
                CountriesGridLayoutAdapter countriesGridLayoutAdapter = new CountriesGridLayoutAdapter(getActivity(), Arrays.asList(mValues));
    
                RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), 2);
                mRecyclerView.setLayoutManager(layoutManager);
                mRecyclerView.addItemDecoration(new GridSpacesItemDecoration(QuickReturnUtils.dp2px(getActivity(), 8)));
    
                mRecyclerView.setAdapter(countriesGridLayoutAdapter);
            }
    
            int footerHeight = getActivity().getResources().getDimensionPixelSize(R.dimen.footer_height);
    
            QuickReturnRecyclerViewOnScrollListener scrollListener;
            SpeedyQuickReturnRecyclerViewOnScrollListener scrollListener2;
    
            switch (mQuickReturnAnimationType){
                case TRANSLATION_SIMPLE:
                    if(mLayoutManagerType.equals("grid")){
                        scrollListener = new QuickReturnRecyclerViewOnScrollListener.Builder(QuickReturnViewType.FOOTER)
                                .footer(mQuickReturnTextView)
                                .minFooterTranslation(footerHeight)
                                .columnCount(2)
                                .build();
                    } else {
                        scrollListener = new QuickReturnRecyclerViewOnScrollListener.Builder(QuickReturnViewType.FOOTER)
                                .footer(mQuickReturnTextView)
                                .minFooterTranslation(footerHeight)
                                .build();
                    }
                    mRecyclerView.setOnScrollListener(scrollListener);
                    break;
                case TRANSLATION_SNAP:
                    if(mLayoutManagerType.equals("grid")){
                        scrollListener = new QuickReturnRecyclerViewOnScrollListener.Builder(QuickReturnViewType.FOOTER)
                                .footer(mQuickReturnTextView)
                                .minFooterTranslation(footerHeight)
                                .columnCount(2)
                                .isSnappable(true)
                                .build();
                    } else {
                        scrollListener = new QuickReturnRecyclerViewOnScrollListener.Builder(QuickReturnViewType.FOOTER)
                                .footer(mQuickReturnTextView)
                                .minFooterTranslation(footerHeight)
                                .isSnappable(true)
                                .build();
                    }
                    mRecyclerView.setOnScrollListener(scrollListener);
                    break;
                case TRANSLATION_ANTICIPATE_OVERSHOOT:
                    if(mLayoutManagerType.equals("grid")){
                        scrollListener2 = new SpeedyQuickReturnRecyclerViewOnScrollListener.Builder(getActivity(), QuickReturnViewType.FOOTER)
                                .footer(mQuickReturnTextView)
                                .columnCount(2)
                                .build();
                    } else {
                        scrollListener2 = new SpeedyQuickReturnRecyclerViewOnScrollListener.Builder(getActivity(), QuickReturnViewType.FOOTER)
                                .footer(mQuickReturnTextView)
                                .build();
                    }
                    mRecyclerView.setOnScrollListener(scrollListener2);
                    break;
                default:
                    if(mLayoutManagerType.equals("grid")){
                        scrollListener = new QuickReturnRecyclerViewOnScrollListener.Builder(QuickReturnViewType.FOOTER)
                                .footer(mQuickReturnTextView)
                                .minFooterTranslation(footerHeight)
                                .columnCount(2)
                                .build();
                    } else {
                        scrollListener = new QuickReturnRecyclerViewOnScrollListener.Builder(QuickReturnViewType.FOOTER)
                                .footer(mQuickReturnTextView)
                                .minFooterTranslation(footerHeight)
                                .build();
                    }
                    mRecyclerView.setOnScrollListener(scrollListener);
                    break;
            }
        }
    
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            ButterKnife.reset(this);
        }
        // endregion
    
    }
    

    QuickReturnRecyclerViewOnScrollListener.java

    public class QuickReturnRecyclerViewOnScrollListener extends RecyclerView.OnScrollListener {
    
        // region Member Variables
        private final QuickReturnViewType mQuickReturnViewType;
        private final View mHeader;
        private final int mMinHeaderTranslation;
        private final View mFooter;
        private final int mMinFooterTranslation;
        private final int mColumnCount;
        private final boolean mIsSnappable; // Can Quick Return view snap into place?
    
        private int mPrevScrollY = 0;
        private int mHeaderDiffTotal = 0;
        private int mFooterDiffTotal = 0;
        private List<RecyclerView.OnScrollListener> mExtraOnScrollListenerList = new ArrayList<>();
        // endregion
    
        // region Constructors
        private QuickReturnRecyclerViewOnScrollListener(Builder builder) {
            mQuickReturnViewType = builder.mQuickReturnViewType;
            mHeader = builder.mHeader;
            mMinHeaderTranslation = builder.mMinHeaderTranslation;
            mFooter = builder.mFooter;
            mMinFooterTranslation = builder.mMinFooterTranslation;
            mColumnCount = builder.mColumnCount;
            mIsSnappable = builder.mIsSnappable;
        }
        // endregion
    
    
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
    
            // apply another list' s on scroll listener
            for (RecyclerView.OnScrollListener listener : mExtraOnScrollListenerList) {
              listener.onScrollStateChanged(recyclerView, newState);
            }
    
            if (newState == RecyclerView.SCROLL_STATE_IDLE && mIsSnappable) {
    
                int midHeader = -mMinHeaderTranslation/2;
                int midFooter = mMinFooterTranslation/2;
    
                switch (mQuickReturnViewType) {
                    case HEADER:
                        if (-mHeaderDiffTotal > 0 && -mHeaderDiffTotal < midHeader) {
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mHeader, "translationY", mHeader.getTranslationY(), 0);
                            anim.setDuration(100);
                            anim.start();
                            mHeaderDiffTotal = 0;
                        } else if (-mHeaderDiffTotal < -mMinHeaderTranslation && -mHeaderDiffTotal >= midHeader) {
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mHeader, "translationY", mHeader.getTranslationY(), mMinHeaderTranslation);
                            anim.setDuration(100);
                            anim.start();
                            mHeaderDiffTotal = mMinHeaderTranslation;
                        }
                        break;
                    case FOOTER:
                        if (-mFooterDiffTotal > 0 && -mFooterDiffTotal < midFooter) { // slide up
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mFooter, "translationY", mFooter.getTranslationY(), 0);
                            anim.setDuration(100);
                            anim.start();
                            mFooterDiffTotal = 0;
                        } else if (-mFooterDiffTotal < mMinFooterTranslation && -mFooterDiffTotal >= midFooter) { // slide down
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mFooter, "translationY", mFooter.getTranslationY(), mMinFooterTranslation);
                            anim.setDuration(100);
                            anim.start();
                            mFooterDiffTotal = -mMinFooterTranslation;
                        }
                        break;
                    case BOTH:
                        if (-mHeaderDiffTotal > 0 && -mHeaderDiffTotal < midHeader) {
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mHeader, "translationY", mHeader.getTranslationY(), 0);
                            anim.setDuration(100);
                            anim.start();
                            mHeaderDiffTotal = 0;
                        } else if (-mHeaderDiffTotal < -mMinHeaderTranslation && -mHeaderDiffTotal >= midHeader) {
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mHeader, "translationY", mHeader.getTranslationY(), mMinHeaderTranslation);
                            anim.setDuration(100);
                            anim.start();
                            mHeaderDiffTotal = mMinHeaderTranslation;
                        }
    
                        if (-mFooterDiffTotal > 0 && -mFooterDiffTotal < midFooter) { // slide up
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mFooter, "translationY", mFooter.getTranslationY(), 0);
                            anim.setDuration(100);
                            anim.start();
                            mFooterDiffTotal = 0;
                        } else if (-mFooterDiffTotal < mMinFooterTranslation && -mFooterDiffTotal >= midFooter) { // slide down
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mFooter, "translationY", mFooter.getTranslationY(), mMinFooterTranslation);
                            anim.setDuration(100);
                            anim.start();
                            mFooterDiffTotal = -mMinFooterTranslation;
                        }
                        break;
                    case TWITTER:
                        if (-mHeaderDiffTotal > 0 && -mHeaderDiffTotal < midHeader) {
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mHeader, "translationY", mHeader.getTranslationY(), 0);
                            anim.setDuration(100);
                            anim.start();
                            mHeaderDiffTotal = 0;
                        } else if (-mHeaderDiffTotal < -mMinHeaderTranslation && -mHeaderDiffTotal >= midHeader) {
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mHeader, "translationY", mHeader.getTranslationY(), mMinHeaderTranslation);
                            anim.setDuration(100);
                            anim.start();
                            mHeaderDiffTotal = mMinHeaderTranslation;
                        }
    
                        if (-mFooterDiffTotal > 0 && -mFooterDiffTotal < midFooter) { // slide up
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mFooter, "translationY", mFooter.getTranslationY(), 0);
                            anim.setDuration(100);
                            anim.start();
                            mFooterDiffTotal = 0;
                        } else if (-mFooterDiffTotal < mMinFooterTranslation && -mFooterDiffTotal >= midFooter) { // slide down
                            ObjectAnimator anim = ObjectAnimator.ofFloat(mFooter, "translationY", mFooter.getTranslationY(), mMinFooterTranslation);
                            anim.setDuration(100);
                            anim.start();
                            mFooterDiffTotal = -mMinFooterTranslation;
                        }
                        break;
                }
    
            }
        }
    
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
    
            // apply extra on scroll listener
            for (RecyclerView.OnScrollListener listener : mExtraOnScrollListenerList) {
              listener.onScrolled(recyclerView, dx, dy);
            }
    
            int scrollY = QuickReturnUtils.getScrollY(recyclerView, mColumnCount);
    //        Log.d("", "onScrolled() : scrollY - "+scrollY);
            int diff = mPrevScrollY - scrollY;
    //        Log.d("", "onScrolled() : diff - "+diff);
    
            if(diff != 0){
                switch (mQuickReturnViewType){
                    case HEADER:
                        if(diff < 0){ // scrolling down
                            mHeaderDiffTotal = Math.max(mHeaderDiffTotal + diff, mMinHeaderTranslation);
                        } else { // scrolling up
                            mHeaderDiffTotal = Math.min(Math.max(mHeaderDiffTotal + diff, mMinHeaderTranslation), 0);
                        }
    
                        mHeader.setTranslationY(mHeaderDiffTotal);
                        break;
                    case FOOTER:
                        if(diff < 0){ // scrolling down
                            mFooterDiffTotal = Math.max(mFooterDiffTotal + diff, -mMinFooterTranslation);
                        } else { // scrolling up
                            mFooterDiffTotal = Math.min(Math.max(mFooterDiffTotal + diff, -mMinFooterTranslation), 0);
                        }
    
                        mFooter.setTranslationY(-mFooterDiffTotal);
                        break;
                    case BOTH:
                        if(diff < 0){ // scrolling down
                            mHeaderDiffTotal = Math.max(mHeaderDiffTotal + diff, mMinHeaderTranslation);
                            mFooterDiffTotal = Math.max(mFooterDiffTotal + diff, -mMinFooterTranslation);
                        } else { // scrolling up
                            mHeaderDiffTotal = Math.min(Math.max(mHeaderDiffTotal + diff, mMinHeaderTranslation), 0);
                            mFooterDiffTotal = Math.min(Math.max(mFooterDiffTotal + diff, -mMinFooterTranslation), 0);
                        }
    
                        mHeader.setTranslationY(mHeaderDiffTotal);
                        mFooter.setTranslationY(-mFooterDiffTotal);
                        break;
                    case TWITTER:
                        if(diff < 0){ // scrolling down
                            if(scrollY > -mMinHeaderTranslation)
                                mHeaderDiffTotal = Math.max(mHeaderDiffTotal + diff, mMinHeaderTranslation);
    
                            if(scrollY > mMinFooterTranslation)
                                mFooterDiffTotal = Math.max(mFooterDiffTotal + diff, -mMinFooterTranslation);
                        } else { // scrolling up
                            mHeaderDiffTotal = Math.min(Math.max(mHeaderDiffTotal + diff, mMinHeaderTranslation), 0);
                            mFooterDiffTotal = Math.min(Math.max(mFooterDiffTotal + diff, -mMinFooterTranslation), 0);
                        }
    
                        mHeader.setTranslationY(mHeaderDiffTotal);
                        mFooter.setTranslationY(-mFooterDiffTotal);
                    default:
                        break;
                }
            }
    
            mPrevScrollY = scrollY;
        }
    
        // region Helper Methods
        public void registerExtraOnScrollListener(RecyclerView.OnScrollListener listener) {
            mExtraOnScrollListenerList.add(listener);
        }
        // endregion
    
        // region Inner Classes
    
        public static class Builder {
            // Required parameters
            private final QuickReturnViewType mQuickReturnViewType;
    
            // Optional parameters - initialized to default values
            private View mHeader = null;
            private int mMinHeaderTranslation = 0;
            private View mFooter = null;
            private int mMinFooterTranslation = 0;
            private int mColumnCount = 1;
            private boolean mIsSnappable = false;
    
            public Builder(QuickReturnViewType quickReturnViewType) {
                mQuickReturnViewType = quickReturnViewType;
            }
    
            public Builder header(View header){
                mHeader = header;
                return this;
            }
    
            public Builder minHeaderTranslation(int minHeaderTranslation){
                mMinHeaderTranslation = minHeaderTranslation;
                return this;
            }
    
            public Builder footer(View footer){
                mFooter = footer;
                return this;
            }
    
            public Builder minFooterTranslation(int minFooterTranslation){
                mMinFooterTranslation = minFooterTranslation;
                return this;
            }
    
            public Builder columnCount(int columnCount){
                mColumnCount = columnCount;
                return this;
            }
    
            public Builder isSnappable(boolean isSnappable){
                mIsSnappable = isSnappable;
                return this;
            }
    
            public QuickReturnRecyclerViewOnScrollListener build() {
                return new QuickReturnRecyclerViewOnScrollListener(this);
            }
        }
    
        // endregion
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-16
      • 2017-08-20
      • 2021-11-03
      • 2017-12-15
      相关资源
      最近更新 更多