zoukankan      html  css  js  c++  java
  • 下拉刷新动画研究

    昨天公司提了一个需求。说是要有自己特色的下拉刷新上拉载入很多其它,随后就去万能的github上面看看自己之前存过的那些。偶然间看到这个Android-AnimatePullToRefreshListView,这玩意能够使用gif图片或者帧动画去运行headview动画载入,而且是基于chrisbanes的Android-PullToRefresh,这样还方便与我项目无缝衔接

    上一张效果图
    这里写图片描写叙述
    大体上简单说明下:
    1.gif与帧动画播放採用的是android-gif-drawable
    2.主题上是改动了RotateLoadingLayout类。看代码

    //帧动画三张图
    private int[] mGifRes = {
                R.drawable.dropdown_loading_00,
                R.drawable.dropdown_loading_01,
                R.drawable.dropdown_loading_02,
        };
    //通过下拉的scale比例,去计算应该显示哪张图片(下拉距离/headview高度)
    protected void onPullImpl(float scaleOfLayout) {
        int index = (int) (scaleOfLayout / 1f * 10);
        if (index == mPrevIndex) {
            return;
        } else {
            if (index > 10) {
                index = 10;
            }
            int res = getResources().getIdentifier(String.format("dropdown_anim_%02d",  index), "drawable", getContext().getPackageName());
            mHeaderImage.setImageResource(res);
            mPrevIndex = index;
        }
    }
    //正在刷新,就播放一下动画
    @Override
    protected void refreshingImpl() {
           if (mGifAnimation == null) {
               mGifAnimation = new GifAnimation(mHeaderImage, mGifRes);
           }
           mGifAnimation.start();
       }
    
    //刷新结束,就停止动画播放
    @Override
    protected void resetImpl() {
           mHeaderImage.clearAnimation();
           if (mGifAnimation != null) {
               mGifAnimation.stop();
           }
    }

    在PullToRefreshBase中能够看到

    /**
         * Actions a Pull Event
         *
         * @return true if the Event has been handled, false if there has been no
         * change
         */
        private void pullEvent() {
            final int newScrollValue;
            final int itemDimension;
            final float initialMotionValue, lastMotionValue;
    
            switch (getPullToRefreshScrollDirection()) {
                case HORIZONTAL:
                    initialMotionValue = mInitialMotionX;
                    lastMotionValue = mLastMotionX;
                    break;
                case VERTICAL:
                default:
                    initialMotionValue = mInitialMotionY;
                    lastMotionValue = mLastMotionY;
                    break;
            }
            //得到对应的高度
            switch (mCurrentMode) {
                case PULL_FROM_END:
                    newScrollValue = Math.round(Math.max(initialMotionValue
                            - lastMotionValue, 0)
                            / FRICTION);
                    itemDimension = getFooterSize();
                    break;
                case PULL_FROM_START:
                default:
                    newScrollValue = Math.round(Math.min(initialMotionValue
                            - lastMotionValue, 0)
                            / FRICTION);
                    itemDimension = getHeaderSize();
                    break;
            }
    
            setHeaderScroll(newScrollValue);
    
            if (newScrollValue != 0 && !isRefreshing()) {
                //通过当前移动的比例跟view自身的高度,计算出scale
                float scale = Math.abs(newScrollValue) / (float) itemDimension;
                //不管你设置的是何种mode。都会有对应的回调
                switch (mCurrentMode) {
                    case PULL_FROM_END:
                        mFooterLayout.onPull(scale);
                        break;
                    case PULL_FROM_START:
                    default:
                        mHeaderLayout.onPull(scale);
                        break;
                }
                //前台接口回调
                if (mState != State.PULL_TO_REFRESH
                        && itemDimension >= Math.abs(newScrollValue)) {
                    setState(State.PULL_TO_REFRESH);
                } else if (mState == State.PULL_TO_REFRESH
                        && itemDimension < Math.abs(newScrollValue)) {
                    setState(State.RELEASE_TO_REFRESH);
                }
            }
        }

    只是这边有个情况要考虑下,就是之前我们能够直接使用ptrDrawable、ptrDrawableStart、ptrDrawableEnd去替换上拉下拉不同的图片

    <!-- Drawable to use as Loading Indicator. Changes both Header and Footer. -->
            <attr name="ptrDrawable" format="reference" />
    
            <!-- Drawable to use as Loading Indicator in the Header View. Overrides value set in ptrDrawable. -->
            <attr name="ptrDrawableStart" format="reference" />
    
            <!-- Drawable to use as Loading Indicator in the Footer View. Overrides value set in ptrDrawable. -->
            <attr name="ptrDrawableEnd" format="reference" />

    可是通过如今代码去构建view的话。这些自己定义属性是不具备这个能力,所以要自行替换foot和head

    // We need to create now layouts now
            mHeaderLayout = createLoadingLayout(context, Mode.PULL_FROM_START, a);
            mFooterLayout = createLoadingLayout(context, Mode.PULL_FROM_END, a);
    
    //创建视图的方法
    protected LoadingLayout createLoadingLayout(Context context, Mode mode, TypedArray attrs) {
            LoadingLayout layout = mLoadingAnimationStyle.createLoadingLayout(
                    context, mode, getPullToRefreshScrollDirection(), attrs);
            layout.setVisibility(View.INVISIBLE);
            return layout;
        }
    
    //能够改造这个枚举。返回须要的layout
    public static enum AnimationStyle {
        /**
         * This is the default for Android-PullToRefresh. Allows you to use any
         * drawable, which is automatically rotated and used as a Progress Bar.
         */
        ROTATE,
    
        /**
         * This is the old default, and what is commonly used on iOS. Uses an
         * arrow image which flips depending on where the user has scrolled.
         */
        FLIP,
    
        GIF;
    
        static AnimationStyle getDefault() {
            return ROTATE;
        }
    
        /**
         * Maps an int to a specific mode. This is needed when saving state, or
         * inflating the view from XML where the mode is given through a attr
         * int.
         *
         * @param modeInt - int to map a Mode to
         * @return Mode that modeInt maps to, or ROTATE by default.
         */
        static AnimationStyle mapIntToValue(int modeInt) {
            switch (modeInt) {
                case 0x0:
                default:
                    return ROTATE;
                case 0x1:
                    return FLIP;
                case 0x10:
                    return GIF;
            }
        }
    
        LoadingLayout createLoadingLayout(Context context, Mode mode,
                                          Orientation scrollDirection, TypedArray attrs) {
            switch (this) {
                case ROTATE:
                default:
                    return new RotateLoadingLayout(context, mode, scrollDirection,
                            attrs);
                case FLIP:
                    return new FlipLoadingLayout(context, mode, scrollDirection,
                            attrs);
                case GIF:
                    return new GifLoadingLayout(context, mode, scrollDirection,
                            attrs);
            }
        }
    }

    仅仅有这样才干创建出不同的head与foot

    OK,今天就说这么多,有疑问大家一起交流

  • 相关阅读:
    Leetcode Plus One
    Leetcode Swap Nodes in Pairs
    Leetcode Remove Nth Node From End of List
    leetcode Remove Duplicates from Sorted Array
    leetcode Remove Element
    leetcode Container With Most Water
    leetcode String to Integer (atoi)
    leetcode Palindrome Number
    leetcode Roman to Integer
    leetcode ZigZag Conversion
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/7082075.html
Copyright © 2011-2022 走看看