【问题标题】:How to implement pullToRefreshListView using JazzyListView?如何使用 JazzyListView 实现 pullToRefreshListView?
【发布时间】:2015-09-23 18:32:52
【问题描述】:

我给你一些提示链接:

  1. https://github.com/twotoasters/jazzylistview

  2. https://play.google.com/store/apps/details?id=com.twotoasters.jazzylistview.sample

我已经实现了JazzylistView,但我还想用PullToRefreshListView 实现JazzylistView。这可能吗?有谁知道这个答案,请帮帮我?

【问题讨论】:

    标签: java android listview animation jazzylistview


    【解决方案1】:

    我找到了这个解决方案。只需将以下代码复制粘贴到库中的 PullToRefreshListView .java 文件中即可。

    package com.smartupdater.widget;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.ViewTreeObserver;
    import android.view.ViewTreeObserver.OnGlobalLayoutListener;
    import android.view.animation.Animation;
    import android.view.animation.Animation.AnimationListener;
    import android.view.animation.LinearInterpolator;
    import android.view.animation.OvershootInterpolator;
    import android.view.animation.RotateAnimation;
    import android.view.animation.TranslateAnimation;
    import android.widget.AdapterView;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.ProgressBar;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    
    import com.notecrate.R;
    import com.smartupdater.utils.Constants;
    
    
    public class PullToRefreshListView extends ListView {
    
        private final JazzyHelper mHelper;
        private static final float PULL_RESISTANCE = 1.7f;
        private static final int BOUNCE_ANIMATION_DURATION = 700;
        private static final int BOUNCE_ANIMATION_DELAY = 100;
        private static final float BOUNCE_OVERSHOOT_TENSION = 1.4f;
        private static final int ROTATE_ARROW_ANIMATION_DURATION = 250;
    
        private static enum State {
            PULL_TO_REFRESH, RELEASE_TO_REFRESH, REFRESHING
        }
    
        /**
         * Interface to implement when you want to get notified of 'pull to refresh'
         * events. Call setOnRefreshListener(..) to activate an OnRefreshListener.
         */
        public interface OnRefreshListener {
    
            /**
             * Method to be called when a refresh is requested
             */
            public void onRefresh();
        }
    
        private static int measuredHeaderHeight;
    
        private boolean scrollbarEnabled;
        private boolean bounceBackHeader;
        private boolean lockScrollWhileRefreshing;
        private boolean showLastUpdatedText;
        private String pullToRefreshText;
        private String releaseToRefreshText;
        private String refreshingText;
        private String lastUpdatedText;
        private SimpleDateFormat lastUpdatedDateFormat = new SimpleDateFormat("dd/MM HH:mm");
    
        private float previousY;
        private int headerPadding;
        private boolean hasResetHeader;
        private long lastUpdated = -1;
        private State state;
        private LinearLayout headerContainer;
        private RelativeLayout header;
        private RotateAnimation flipAnimation;
        private RotateAnimation reverseFlipAnimation;
        private ImageView image;
        private ProgressBar spinner;
        private TextView text;
        private TextView lastUpdatedTextView;
        private OnItemClickListener onItemClickListener;
        private OnItemLongClickListener onItemLongClickListener;
        private OnRefreshListener onRefreshListener;
    
        public PullToRefreshListView(Context context) {
            super(context);
            mHelper = init(context, null);
            init();
        }
    
        public PullToRefreshListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            mHelper = init(context, attrs);
            init();
        }
    
        public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            mHelper = init(context, attrs);
            init();
        }
    
        private JazzyHelper init(Context context, AttributeSet attrs) {
            JazzyHelper helper = new JazzyHelper(context, attrs);
            super.setOnScrollListener(helper);
            return helper;
        }
    
        @Override
        public final void setOnScrollListener(OnScrollListener l) {
            mHelper.setOnScrollListener(l);
        }
    
        public void setTransitionEffect(int transitionEffect) {
            mHelper.setTransitionEffect(transitionEffect);
        }
    
        public void setShouldOnlyAnimateNewItems(boolean onlyAnimateNew) {
            mHelper.setShouldOnlyAnimateNewItems(onlyAnimateNew);
        }
    
        public void setShouldOnlyAnimateFling(boolean onlyFling) {
            mHelper.setShouldOnlyAnimateFling(onlyFling);
        }
    
        public void setSimulateGridWithList(boolean simulateGridWithList) {
            mHelper.setSimulateGridWithList(simulateGridWithList);
            setClipChildren(!simulateGridWithList);
        }
    
        public void setMaxAnimationVelocity(int itemsPerSecond) {
            mHelper.setMaxAnimationVelocity(itemsPerSecond);
        }
    
        @Override
        public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
            this.onItemClickListener = onItemClickListener;
        }
    
        @Override
        public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
            this.onItemLongClickListener = onItemLongClickListener;
        }
    
        /**
         * Activate an OnRefreshListener to get notified on 'pull to refresh'
         * events.
         * 
         * @param onRefreshListener
         *            The OnRefreshListener to get notified
         */
        public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
            this.onRefreshListener = onRefreshListener;
        }
    
        /**
         * @return If the list is in 'Refreshing' state
         */
        public boolean isRefreshing() {
            return state == State.REFRESHING;
        }
    
        /**
         * Default is false. When lockScrollWhileRefreshing is set to true, the list
         * cannot scroll when in 'refreshing' mode. It's 'locked' on refreshing.
         * 
         * @param lockScrollWhileRefreshing
         */
        public void setLockScrollWhileRefreshing(boolean lockScrollWhileRefreshing) {
            this.lockScrollWhileRefreshing = lockScrollWhileRefreshing;
        }
    
        /**
         * Default is false. Show the last-updated date/time in the 'Pull ro
         * Refresh' header. See 'setLastUpdatedDateFormat' to set the date/time
         * formatting.
         * 
         * @param showLastUpdatedText
         */
        public void setShowLastUpdatedText(boolean showLastUpdatedText) {
            this.showLastUpdatedText = showLastUpdatedText;
            if (!showLastUpdatedText)
                lastUpdatedTextView.setVisibility(View.GONE);
        }
    
        /**
         * Default: "dd/MM HH:mm". Set the format in which the last-updated
         * date/time is shown. Meaningless if 'showLastUpdatedText == false
         * (default)'. See 'setShowLastUpdatedText'.
         * 
         * @param lastUpdatedDateFormat
         */
        public void setLastUpdatedDateFormat(SimpleDateFormat lastUpdatedDateFormat) {
            this.lastUpdatedDateFormat = lastUpdatedDateFormat;
        }
    
        /**
         * Explicitly set the state to refreshing. This is useful when you want to
         * show the spinner and 'Refreshing' text when the refresh was not triggered
         * by 'pull to refresh', for example on start.
         */
        public void setRefreshing() {
            state = State.REFRESHING;
            scrollTo(0, 0);
            setUiRefreshing();
            setHeaderPadding(0);
        }
    
        /**
         * Set the state back to 'pull to refresh'. Call this method when refreshing
         * the data is finished.
         */
        public void onRefreshComplete() {
            state = State.PULL_TO_REFRESH;
            resetHeader();
            lastUpdated = System.currentTimeMillis();
        }
    
        /**
         * Change the label text on state 'Pull to Refresh'
         * 
         * @param pullToRefreshText
         *            Text
         */
        public void setTextPullToRefresh(String pullToRefreshText) {
            this.pullToRefreshText = pullToRefreshText;
            if (state == State.PULL_TO_REFRESH) {
                text.setText(pullToRefreshText);
            }
        }
    
        /**
         * Change the label text on state 'Release to Refresh'
         * 
         * @param releaseToRefreshText
         *            Text
         */
        public void setTextReleaseToRefresh(String releaseToRefreshText) {
            this.releaseToRefreshText = releaseToRefreshText;
            if (state == State.RELEASE_TO_REFRESH) {
                text.setText(releaseToRefreshText);
            }
        }
    
        /**
         * Change the label text on state 'Refreshing'
         * 
         * @param refreshingText
         *            Text
         */
        public void setTextRefreshing(String refreshingText) {
            this.refreshingText = refreshingText;
            if (state == State.REFRESHING) {
                text.setText(refreshingText);
            }
        }
    
        private void init() {
            setVerticalFadingEdgeEnabled(false);
    
            headerContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.layout_pulldown_header, null);
            header = (RelativeLayout) headerContainer.findViewById(R.id.ptr_id_header);
            text = (TextView) header.findViewById(R.id.ptr_id_text);
            lastUpdatedTextView = (TextView) header.findViewById(R.id.ptr_id_last_updated);
            image = (ImageView) header.findViewById(R.id.ptr_id_image);
            spinner = (ProgressBar) header.findViewById(R.id.ptr_id_spinner);
    
            pullToRefreshText = getContext().getString(R.string.ptr_pull_to_refresh);
            releaseToRefreshText = getContext().getString(R.string.ptr_release_to_refresh);
            refreshingText = getContext().getString(R.string.ptr_refreshing);
            lastUpdatedText = getContext().getString(R.string.ptr_last_updated);
    
            flipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
            flipAnimation.setInterpolator(new LinearInterpolator());
            flipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION);
            flipAnimation.setFillAfter(true);
    
            reverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
            reverseFlipAnimation.setInterpolator(new LinearInterpolator());
            reverseFlipAnimation.setDuration(ROTATE_ARROW_ANIMATION_DURATION);
            reverseFlipAnimation.setFillAfter(true);
    
            addHeaderView(headerContainer);
            setState(State.PULL_TO_REFRESH);
            scrollbarEnabled = isVerticalScrollBarEnabled();
    
            ViewTreeObserver vto = header.getViewTreeObserver();
            vto.addOnGlobalLayoutListener(new PTROnGlobalLayoutListener());
    
            super.setOnItemClickListener(new PTROnItemClickListener());
            super.setOnItemLongClickListener(new PTROnItemLongClickListener());
        }
    
        private void setHeaderPadding(int padding) {
            headerPadding = padding;
            // Log.d(Constants.TAG, "Header Container=" + headerContainer +
            // " Header=" + header + " Header Padding=" + headerPadding);
            if (header != null) {
                MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) header.getLayoutParams();
                mlp.setMargins(0, Math.round(padding), 0, 0);
                header.setLayoutParams(mlp);
            }
        }                                                                                                     
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (lockScrollWhileRefreshing && (state == State.REFRESHING || getAnimation() != null && !getAnimation().hasEnded())) {
                return true;
            }
    
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (getFirstVisiblePosition() == 0)
                    previousY = event.getY();
                else
                    previousY = -1;
                break;
    
            case MotionEvent.ACTION_UP:
                if (previousY != -1 && (state == State.RELEASE_TO_REFRESH || getFirstVisiblePosition() == 0)) {
                    switch (state) {
                    case RELEASE_TO_REFRESH:
                        setState(State.REFRESHING);
                        bounceBackHeader();
    
                        break;
    
                    case PULL_TO_REFRESH:
                        resetHeader();
                        break;
                    }
                }
                break;
    
            case MotionEvent.ACTION_MOVE:
                if (previousY != -1) {
                    float y = event.getY();
                    float diff = y - previousY;
                    if (diff > 0)
                        diff /= PULL_RESISTANCE;
                    previousY = y;
    
                    int newHeaderPadding = Math.max(Math.round(headerPadding + diff), -header.getHeight());
    
                    if (newHeaderPadding != headerPadding && state != State.REFRESHING) {
                        setHeaderPadding(newHeaderPadding);
    
                        if (state == State.PULL_TO_REFRESH && headerPadding > 0) {
                            setState(State.RELEASE_TO_REFRESH);
    
                            image.clearAnimation();
                            image.startAnimation(flipAnimation);
                        } else if (state == State.RELEASE_TO_REFRESH && headerPadding < 0) {
                            setState(State.PULL_TO_REFRESH);
    
                            image.clearAnimation();
                            image.startAnimation(reverseFlipAnimation);
                        }
    
                        return true;
                    }
                }
    
                break;
            }
    
            return super.onTouchEvent(event);
        }
    
        private void bounceBackHeader() {
            int yTranslate = state == State.REFRESHING ? header.getHeight() - headerContainer.getHeight() : -headerContainer.getHeight()
                    - headerContainer.getTop();
    
            TranslateAnimation bounceAnimation = new TranslateAnimation(TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, 0,
                    TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, yTranslate);
    
            bounceAnimation.setDuration(BOUNCE_ANIMATION_DURATION);
            bounceAnimation.setFillEnabled(true);
            bounceAnimation.setFillAfter(false);
            bounceAnimation.setFillBefore(true);
            bounceAnimation.setInterpolator(new OvershootInterpolator(BOUNCE_OVERSHOOT_TENSION));
            bounceAnimation.setAnimationListener(new HeaderAnimationListener(yTranslate));
    
            startAnimation(bounceAnimation);
        }
    
        private void resetHeader() {
            if (getFirstVisiblePosition() > 0) {
                setHeaderPadding(-header.getHeight());
                setState(State.PULL_TO_REFRESH);
                return;
            }
    
            if (getAnimation() != null && !getAnimation().hasEnded()) {
                bounceBackHeader = true;
            } else {
                bounceBackHeader();
            }
        }
    
        private void setUiRefreshing() {
            spinner.setVisibility(View.VISIBLE);
            image.clearAnimation();
            image.setVisibility(View.INVISIBLE);
            text.setText(refreshingText);
        }
    
        private void setState(State state) {
            this.state = state;
            switch (state) {
            case PULL_TO_REFRESH:
                spinner.setVisibility(View.INVISIBLE);
                image.setVisibility(View.VISIBLE);
                text.setText(pullToRefreshText);
    
                if (showLastUpdatedText && lastUpdated != -1) {
                    lastUpdatedTextView.setVisibility(View.VISIBLE);
                    lastUpdatedTextView.setText(String.format(lastUpdatedText, lastUpdatedDateFormat.format(new Date(lastUpdated))));
                }
    
                break;
    
            case RELEASE_TO_REFRESH:
                spinner.setVisibility(View.INVISIBLE);
                image.setVisibility(View.VISIBLE);
                text.setText(releaseToRefreshText);
                break;
    
            case REFRESHING:
                setUiRefreshing();
    
                lastUpdated = System.currentTimeMillis();
                if (onRefreshListener == null) {
                    setState(State.PULL_TO_REFRESH);
                } else {
                    onRefreshListener.onRefresh();
                }
    
                break;
            }
        }
    
        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
    
            if (!hasResetHeader) {
                if (measuredHeaderHeight > 0 && state != State.REFRESHING) {
                    setHeaderPadding(-measuredHeaderHeight);
                }
    
                hasResetHeader = true;
            }
        }
    
        private class HeaderAnimationListener implements AnimationListener {
    
            private int height, translation;
            private State stateAtAnimationStart;
    
            public HeaderAnimationListener(int translation) {
                this.translation = translation;
            }
    
            @Override
            public void onAnimationStart(Animation animation) {
                stateAtAnimationStart = state;
    
                android.view.ViewGroup.LayoutParams lp = getLayoutParams();
                height = lp.height;
                lp.height = getHeight() - translation;
                setLayoutParams(lp);
    
                if (scrollbarEnabled) {
                    setVerticalScrollBarEnabled(false);
                }
            }
    
            @Override
            public void onAnimationEnd(Animation animation) {
                setHeaderPadding(stateAtAnimationStart == State.REFRESHING ? 0 : -measuredHeaderHeight - headerContainer.getTop());
                setSelection(0);
    
                android.view.ViewGroup.LayoutParams lp = getLayoutParams();
                lp.height = height;
                setLayoutParams(lp);
    
                if (scrollbarEnabled) {
                    setVerticalScrollBarEnabled(true);
                }
    
                if (bounceBackHeader) {
                    bounceBackHeader = false;
    
                    postDelayed(new Runnable() {
    
                        @Override
                        public void run() {
                            resetHeader();
                        }
                    }, BOUNCE_ANIMATION_DELAY);
                } else if (stateAtAnimationStart != State.REFRESHING) {
                    setState(State.PULL_TO_REFRESH);
                }
            }
    
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        }
    
        private class PTROnGlobalLayoutListener implements OnGlobalLayoutListener {
    
            @Override
            public void onGlobalLayout() {
                int initialHeaderHeight = header.getHeight();
    
                if (initialHeaderHeight > 0) {
                    measuredHeaderHeight = initialHeaderHeight;
    
                    if (measuredHeaderHeight > 0 && state != State.REFRESHING) {
                        setHeaderPadding(-measuredHeaderHeight);
                        requestLayout();
                    }
                }
    
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
            }
        }
    
        private class PTROnItemClickListener implements OnItemClickListener {
    
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                hasResetHeader = false;
    
                if (onItemClickListener != null && state == State.PULL_TO_REFRESH) {
                    // Passing up onItemClick. Correct position with the number of
                    // header views
                    onItemClickListener.onItemClick(adapterView, view, position - getHeaderViewsCount(), id);
                }
            }
        }
    
        private class PTROnItemLongClickListener implements OnItemLongClickListener {
    
            @Override
            public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
                hasResetHeader = false;
    
                if (onItemLongClickListener != null && state == State.PULL_TO_REFRESH) {
                    // Passing up onItemLongClick. Correct position with the number
                    // of header views
                    return onItemLongClickListener.onItemLongClick(adapterView, view, position - getHeaderViewsCount(), id);
                }
    
                return false;
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      其实你可以通过修改源代码来组合这两个框架。 首先,修改 PullToRefreshAdapterViewBase.java

      删除final,因为你已经在PullToRefreshListView中覆盖了它。目的是劫持OnScrollListener,将它传递给JazzyHelper。

      public void setOnScrollListener(OnScrollListener listener) {
          mOnScrollListener = listener;
      }
      

      PullToRefreshListView.java 中的代码。

      /*******************************************************************************
       * Copyright 2011, 2012 Chris Banes.
       *
       * Licensed under the Apache License, Version 2.0 (the "License");
       * you may not use this file except in compliance with the License.
       * You may obtain a copy of the License at
       *
       * http://www.apache.org/licenses/LICENSE-2.0
       *
       * Unless required by applicable law or agreed to in writing, software
       * distributed under the License is distributed on an "AS IS" BASIS,
       * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       * See the License for the specific language governing permissions and
       * limitations under the License.
       *******************************************************************************/
      package com.handmark.pulltorefresh.library;
      
      import com.example.jazzydemo.R;
      import com.handmark.pulltorefresh.library.internal.EmptyViewMethodAccessor;
      import com.handmark.pulltorefresh.library.internal.LoadingLayout;
      import com.xp.lvbh.others.jazzylistview.JazzyEffect;
      import com.xp.lvbh.others.jazzylistview.JazzyHelper;
      
      import android.annotation.TargetApi;
      import android.content.Context;
      import android.content.res.TypedArray;
      import android.graphics.Canvas;
      import android.os.Build.VERSION;
      import android.os.Build.VERSION_CODES;
      import android.util.AttributeSet;
      import android.view.Gravity;
      import android.view.MotionEvent;
      import android.view.View;
      import android.widget.FrameLayout;
      import android.widget.ListAdapter;
      import android.widget.ListView;
      import android.widget.AbsListView.OnScrollListener;
      
      public class PullToRefreshListView extends PullToRefreshAdapterViewBase<ListView> {
      
          private final JazzyHelper mHelper;
      
          private LoadingLayout mHeaderLoadingView;
          private LoadingLayout mFooterLoadingView;
      
          private FrameLayout mLvFooterLoadingFrame;
      
          private boolean mListViewExtrasEnabled;
      
          public PullToRefreshListView(Context context) {
              super(context);
              mHelper = init(context, null);
          }
      
          public PullToRefreshListView(Context context, AttributeSet attrs) {
              super(context, attrs);
              mHelper = init(context, null);
          }
      
          public PullToRefreshListView(Context context, Mode mode) {
              super(context, mode);
              mHelper = init(context, null);
          }
      
          public PullToRefreshListView(Context context, Mode mode, AnimationStyle style) {
              super(context, mode, style);
              mHelper = init(context, null);
          }
      
          @Override
          public final Orientation getPullToRefreshScrollDirection() {
              return Orientation.VERTICAL;
          }
      
          @Override
          protected void onRefreshing(final boolean doScroll) {
              /**
               * If we're not showing the Refreshing view, or the list is empty, the
               * the header/footer views won't show so we use the normal method.
               */
              ListAdapter adapter = mRefreshableView.getAdapter();
              if (!mListViewExtrasEnabled || !getShowViewWhileRefreshing() || null == adapter || adapter.isEmpty()) {
                  super.onRefreshing(doScroll);
                  return;
              }
      
              super.onRefreshing(false);
      
              final LoadingLayout origLoadingView, listViewLoadingView, oppositeListViewLoadingView;
              final int selection, scrollToY;
      
              switch (getCurrentMode()) {
                  case MANUAL_REFRESH_ONLY:
                  case PULL_FROM_END:
                      origLoadingView = getFooterLayout();
                      listViewLoadingView = mFooterLoadingView;
                      oppositeListViewLoadingView = mHeaderLoadingView;
                      selection = mRefreshableView.getCount() - 1;
                      scrollToY = getScrollY() - getFooterSize();
                      break;
                  case PULL_FROM_START:
                  default:
                      origLoadingView = getHeaderLayout();
                      listViewLoadingView = mHeaderLoadingView;
                      oppositeListViewLoadingView = mFooterLoadingView;
                      selection = 0;
                      scrollToY = getScrollY() + getHeaderSize();
                      break;
              }
      
              // Hide our original Loading View
              origLoadingView.reset();
              origLoadingView.hideAllViews();
      
              // Make sure the opposite end is hidden too
              oppositeListViewLoadingView.setVisibility(View.GONE);
      
              // Show the ListView Loading View and set it to refresh.
              listViewLoadingView.setVisibility(View.VISIBLE);
              listViewLoadingView.refreshing();
      
              if (doScroll) {
                  // We need to disable the automatic visibility changes for now
                  disableLoadingLayoutVisibilityChanges();
      
                  // We scroll slightly so that the ListView's header/footer is at the
                  // same Y position as our normal header/footer
                  setHeaderScroll(scrollToY);
      
                  // Make sure the ListView is scrolled to show the loading
                  // header/footer
                  mRefreshableView.setSelection(selection);
      
                  // Smooth scroll as normal
                  smoothScrollTo(0);
              }
          }
      
          @Override
          protected void onReset() {
              /**
               * If the extras are not enabled, just call up to super and return.
               */
              if (!mListViewExtrasEnabled) {
                  super.onReset();
                  return;
              }
      
              final LoadingLayout originalLoadingLayout, listViewLoadingLayout;
              final int scrollToHeight, selection;
              final boolean scrollLvToEdge;
      
              switch (getCurrentMode()) {
                  case MANUAL_REFRESH_ONLY:
                  case PULL_FROM_END:
                      originalLoadingLayout = getFooterLayout();
                      listViewLoadingLayout = mFooterLoadingView;
                      selection = mRefreshableView.getCount() - 1;
                      scrollToHeight = getFooterSize();
                      scrollLvToEdge = Math.abs(mRefreshableView.getLastVisiblePosition() - selection) <= 1;
                      break;
                  case PULL_FROM_START:
                  default:
                      originalLoadingLayout = getHeaderLayout();
                      listViewLoadingLayout = mHeaderLoadingView;
                      scrollToHeight = -getHeaderSize();
                      selection = 0;
                      scrollLvToEdge = Math.abs(mRefreshableView.getFirstVisiblePosition() - selection) <= 1;
                      break;
              }
      
              // If the ListView header loading layout is showing, then we need to
              // flip so that the original one is showing instead
              if (listViewLoadingLayout.getVisibility() == View.VISIBLE) {
      
                  // Set our Original View to Visible
                  originalLoadingLayout.showInvisibleViews();
      
                  // Hide the ListView Header/Footer
                  listViewLoadingLayout.setVisibility(View.GONE);
      
                  /**
                   * Scroll so the View is at the same Y as the ListView
                   * header/footer, but only scroll if: we've pulled to refresh, it's
                   * positioned correctly
                   */
                  if (scrollLvToEdge && getState() != State.MANUAL_REFRESHING) {
                      mRefreshableView.setSelection(selection);
                      setHeaderScroll(scrollToHeight);
                  }
              }
      
              // Finally, call up to super
              super.onReset();
          }
      
          @Override
          protected LoadingLayoutProxy createLoadingLayoutProxy(final boolean includeStart, final boolean includeEnd) {
              LoadingLayoutProxy proxy = super.createLoadingLayoutProxy(includeStart, includeEnd);
      
              if (mListViewExtrasEnabled) {
                  final Mode mode = getMode();
      
                  if (includeStart && mode.showHeaderLoadingLayout()) {
                      proxy.addLayout(mHeaderLoadingView);
                  }
                  if (includeEnd && mode.showFooterLoadingLayout()) {
                      proxy.addLayout(mFooterLoadingView);
                  }
              }
      
              return proxy;
          }
      
          protected ListView createListView(Context context, AttributeSet attrs) {
              final ListView lv;
              if (VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) {
                  lv = new InternalListViewSDK9(context, attrs);
              } else {
                  lv = new InternalListView(context, attrs);
              }
              return lv;
          }
      
          @Override
          protected ListView createRefreshableView(Context context, AttributeSet attrs) {
              ListView lv = createListView(context, attrs);
      
              // Set it to this so it can be used in ListActivity/ListFragment
              lv.setId(android.R.id.list);
              return lv;
          }
      
          @Override
          protected void handleStyledAttributes(TypedArray a) {
              super.handleStyledAttributes(a);
      
              mListViewExtrasEnabled = a.getBoolean(R.styleable.PullToRefresh_ptrListViewExtrasEnabled, true);
      
              if (mListViewExtrasEnabled) {
                  final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                          FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL);
      
                  // Create Loading Views ready for use later
                  FrameLayout frame = new FrameLayout(getContext());
                  mHeaderLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_START, a);
                  mHeaderLoadingView.setVisibility(View.GONE);
                  frame.addView(mHeaderLoadingView, lp);
                  mRefreshableView.addHeaderView(frame, null, false);
      
                  mLvFooterLoadingFrame = new FrameLayout(getContext());
                  mFooterLoadingView = createLoadingLayout(getContext(), Mode.PULL_FROM_END, a);
                  mFooterLoadingView.setVisibility(View.GONE);
                  mLvFooterLoadingFrame.addView(mFooterLoadingView, lp);
      
                  /**
                   * If the value for Scrolling While Refreshing hasn't been
                   * explicitly set via XML, enable Scrolling While Refreshing.
                   */
                  if (!a.hasValue(R.styleable.PullToRefresh_ptrScrollingWhileRefreshingEnabled)) {
                      setScrollingWhileRefreshingEnabled(true);
                  }
              }
          }
      
          @TargetApi(9)
          final class InternalListViewSDK9 extends InternalListView {
      
              public InternalListViewSDK9(Context context, AttributeSet attrs) {
                  super(context, attrs);
              }
      
              @Override
              protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX,
                      int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
      
                  final boolean returnValue = super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
                          scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
      
                  // Does all of the hard work...
                  OverscrollHelper.overScrollBy(PullToRefreshListView.this, deltaX, scrollX, deltaY, scrollY, isTouchEvent);
      
                  return returnValue;
              }
          }
      
          protected class InternalListView extends ListView implements EmptyViewMethodAccessor {
      
              private boolean mAddedLvFooter = false;
      
              public InternalListView(Context context, AttributeSet attrs) {
                  super(context, attrs);
              }
      
              @Override
              protected void dispatchDraw(Canvas canvas) {
                  /**
                   * This is a bit hacky, but Samsung's ListView has got a bug in it
                   * when using Header/Footer Views and the list is empty. This masks
                   * the issue so that it doesn't cause an FC. See Issue #66.
                   */
                  try {
                      super.dispatchDraw(canvas);
                  } catch (IndexOutOfBoundsException e) {
                      e.printStackTrace();
                  }
              }
      
              @Override
              public boolean dispatchTouchEvent(MotionEvent ev) {
                  /**
                   * This is a bit hacky, but Samsung's ListView has got a bug in it
                   * when using Header/Footer Views and the list is empty. This masks
                   * the issue so that it doesn't cause an FC. See Issue #66.
                   */
                  try {
                      return super.dispatchTouchEvent(ev);
                  } catch (IndexOutOfBoundsException e) {
                      e.printStackTrace();
                      return false;
                  }
              }
      
              @Override
              public void setAdapter(ListAdapter adapter) {
                  // Add the Footer View at the last possible moment
                  if (null != mLvFooterLoadingFrame && !mAddedLvFooter) {
                      addFooterView(mLvFooterLoadingFrame, null, false);
                      mAddedLvFooter = true;
                  }
      
                  super.setAdapter(adapter);
              }
      
              @Override
              public void setEmptyView(View emptyView) {
                  PullToRefreshListView.this.setEmptyView(emptyView);
              }
      
              @Override
              public void setEmptyViewInternal(View emptyView) {
                  super.setEmptyView(emptyView);
              }
      
          }
          //add jazzy listview
          /**
           * Sets the desired transition effect.
           *
           * @param transitionEffect The non-bundled transition provided by the client.
           */
          public void setTransitionEffect(JazzyEffect transitionEffect) {
              mHelper.setTransitionEffect(transitionEffect);
          }
      
          @Override
          public void setOnScrollListener(OnScrollListener l) {
              mHelper.setOnScrollListener(l);
          }
      
          private JazzyHelper init(Context context, AttributeSet attrs) {
              JazzyHelper helper = new JazzyHelper(context, attrs);
              super.setOnScrollListener(helper);
              return helper;
          }
      }
      

      我已经验证了代码。希望可以帮助您。 这是一个demo,你可以试试: https://github.com/XIONGDEYI/PullToRefreshListViewAndJazzyListView

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-25
        相关资源
        最近更新 更多