1. 程式人生 > >下拉刷新動畫研究

下拉刷新動畫研究

而且 thead index 技術 alt 動畫播放 view動畫 set ips

昨天公司提了一個需求。說是要有自己特色的下拉刷新上拉載入很多其它,隨後就去萬能的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,今天就說這麽多,有疑問大家一起交流

下拉刷新動畫研究