禁用ViewPager左右兩側拉到邊界的漸變顏色


 

Android ViewPager在拖拽到左邊和右邊的時候,禁止顯示黃色或者藍色的漸變圖片的解決方法

 

先說明哦,想看看院里的,從頭開始看,否則,就拉到最下面啦。解決方案就在最下面。

修改前:

 

修改后:

 

 

 

先看下ViewPager中和這個顏色相關的代碼:

 

private EdgeEffectCompat mLeftEdge;

private EdgeEffectCompat mRightEdge;

就是這倆貨,導致的邊界顏色。沒辦法,這貨是private的,后面只能通過反射來得到了。

再看下draw()方法中的邏輯:

@Override

public void draw(Canvas canvas) {

super.draw(canvas);

boolean needsInvalidate = false;

 

final int overScrollMode = ViewCompat.getOverScrollMode(this);

if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||

(overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS &&

mAdapter != null && mAdapter.getCount() > 1)) {

if (!mLeftEdge.isFinished()) {

final int restoreCount = canvas.save();

final int height = getHeight() - getPaddingTop() - getPaddingBottom();

 

canvas.rotate(270);

canvas.translate(-height + getPaddingTop(), 0);

mLeftEdge.setSize(height, getWidth());

needsInvalidate |= mLeftEdge.draw(canvas);

canvas.restoreToCount(restoreCount);

}

if (!mRightEdge.isFinished()) {

final int restoreCount = canvas.save();

final int width = getWidth();

final int height = getHeight() - getPaddingTop() - getPaddingBottom();

final int itemCount = mAdapter != null ? mAdapter.getCount() : 1;

 

canvas.rotate(90);

canvas.translate(-getPaddingTop(),

-itemCount * (width + mPageMargin) + mPageMargin);

mRightEdge.setSize(height, width);

needsInvalidate |= mRightEdge.draw(canvas);

canvas.restoreToCount(restoreCount);

}

} else {

mLeftEdge.finish();

mRightEdge.finish();

}

 

if (needsInvalidate) {

// Keep animating

invalidate();

}

}

 

在進行繪制漸變圖片之前會判斷是否已經finish,【if (!mLeftEdge.isFinished())】,如果我們能修改為finished狀態,不就OK了嗎?!經過測試,調用mLeftEdge.finish()和mRightEdge.finish()就能達到我們要的結果。但是悲催的是,draw()方法是隨時隨地都在調用的,所以要在一個在draw()方法之后調用,但是還得隨時隨地調用的方法才行。

 

好吧,先說點原理的東東。

ViewPager.javaàdraw()方法 à mRightEdge.draw(canvas);以及mLeftEdge.draw(canvas);à EdgeEffectCompat.javaà看下全部的代碼吧:

public class EdgeEffectCompat {

private Object mEdgeEffect;

 

private static final EdgeEffectImpl IMPL;

 

static {

if (Build.VERSION.SDK_INT >= 14) { // ICS

IMPL = new EdgeEffectIcsImpl();

} else {

IMPL = new BaseEdgeEffectImpl();

}

}

 

interface EdgeEffectImpl {

public Object newEdgeEffect(Context context);

public void setSize(Object edgeEffect, int width, int height);

public boolean isFinished(Object edgeEffect);

public void finish(Object edgeEffect);

public boolean onPull(Object edgeEffect, float deltaDistance);

public boolean onRelease(Object edgeEffect);

public boolean onAbsorb(Object edgeEffect, int velocity);

public boolean draw(Object edgeEffect, Canvas canvas);

}

 

/**

* Null implementation to use pre-ICS

*/

static class BaseEdgeEffectImpl implements EdgeEffectImpl {

public Object newEdgeEffect(Context context) {

return null;

}

 

public void setSize(Object edgeEffect, int width, int height) {

}

 

public boolean isFinished(Object edgeEffect) {

return true;

}

 

public void finish(Object edgeEffect) {

}

 

public boolean onPull(Object edgeEffect, float deltaDistance) {

return false;

}

 

public boolean onRelease(Object edgeEffect) {

return false;

}

 

public boolean onAbsorb(Object edgeEffect, int velocity) {

return false;

}

 

public boolean draw(Object edgeEffect, Canvas canvas) {

return false;

}

}

 

static class EdgeEffectIcsImpl implements EdgeEffectImpl {

public Object newEdgeEffect(Context context) {

return EdgeEffectCompatIcs.newEdgeEffect(context);

}

 

public void setSize(Object edgeEffect, int width, int height) {

EdgeEffectCompatIcs.setSize(edgeEffect, width, height);

}

 

public boolean isFinished(Object edgeEffect) {

return EdgeEffectCompatIcs.isFinished(edgeEffect);

}

 

public void finish(Object edgeEffect) {

EdgeEffectCompatIcs.finish(edgeEffect);

}

 

public boolean onPull(Object edgeEffect, float deltaDistance) {

return EdgeEffectCompatIcs.onPull(edgeEffect, deltaDistance);

}

 

public boolean onRelease(Object edgeEffect) {

return EdgeEffectCompatIcs.onRelease(edgeEffect);

}

 

public boolean onAbsorb(Object edgeEffect, int velocity) {

return EdgeEffectCompatIcs.onAbsorb(edgeEffect, velocity);

}

 

public boolean draw(Object edgeEffect, Canvas canvas) {

return EdgeEffectCompatIcs.draw(edgeEffect, canvas);

}

}

 

/**

* Construct a new EdgeEffect themed using the given context.

*

* <p>Note: On platform versions that do not support EdgeEffect, all operations

* on the newly constructed object will be mocked/no-ops.</p>

*

* @param context Context to use for theming the effect

*/

public EdgeEffectCompat(Context context) {

mEdgeEffect = IMPL.newEdgeEffect(context);

}

 

/**

* Set the size of this edge effect in pixels.

*

* @param width Effect width in pixels

* @param height Effect height in pixels

*/

public void setSize(int width, int height) {

IMPL.setSize(mEdgeEffect, width, height);

}

 

/**

* Reports if this EdgeEffectCompat's animation is finished. If this method returns false

* after a call to {@link #draw(Canvas)} the host widget should schedule another

* drawing pass to continue the animation.

*

* @return true if animation is finished, false if drawing should continue on the next frame.

*/

public boolean isFinished() {

return IMPL.isFinished(mEdgeEffect);

}

 

/**

* Immediately finish the current animation.

* After this call {@link #isFinished()} will return true.

*/

public void finish() {

IMPL.finish(mEdgeEffect);

}

 

/**

* A view should call this when content is pulled away from an edge by the user.

* This will update the state of the current visual effect and its associated animation.

* The host view should always {@link android.view.View#invalidate()} if this method

* returns true and draw the results accordingly.

*

* @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to

* 1.f (full length of the view) or negative values to express change

* back toward the edge reached to initiate the effect.

* @return true if the host view should call invalidate, false if it should not.

*/

public boolean onPull(float deltaDistance) {

return IMPL.onPull(mEdgeEffect, deltaDistance);

}

 

/**

* Call when the object is released after being pulled.

* This will begin the "decay" phase of the effect. After calling this method

* the host view should {@link android.view.View#invalidate()} if this method

* returns true and thereby draw the results accordingly.

*

* @return true if the host view should invalidate, false if it should not.

*/

public boolean onRelease() {

return IMPL.onRelease(mEdgeEffect);

}

 

/**

* Call when the effect absorbs an impact at the given velocity.

* Used when a fling reaches the scroll boundary.

*

* <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},

* the method <code>getCurrVelocity</code> will provide a reasonable approximation

* to use here.</p>

*

* @param velocity Velocity at impact in pixels per second.

* @return true if the host view should invalidate, false if it should not.

*/

public boolean onAbsorb(int velocity) {

return IMPL.onAbsorb(mEdgeEffect, velocity);

}

 

/**

* Draw into the provided canvas. Assumes that the canvas has been rotated

* accordingly and the size has been set. The effect will be drawn the full

* width of X=0 to X=width, beginning from Y=0 and extending to some factor <

* 1.f of height.

*

* @param canvas Canvas to draw into

* @return true if drawing should continue beyond this frame to continue the

* animation

*/

public boolean draw(Canvas canvas) {

return IMPL.draw(mEdgeEffect, canvas);

}

}

 

à看完之后,下面進入到EdgeEffectCompatIcs.javaà好吧,再貼上完整的代碼

class EdgeEffectCompatIcs {

public static Object newEdgeEffect(Context context) {

return new EdgeEffect(context);

}

 

public static void setSize(Object edgeEffect, int width, int height) {

((EdgeEffect) edgeEffect).setSize(width, height);

}

 

public static boolean isFinished(Object edgeEffect) {

return ((EdgeEffect) edgeEffect).isFinished();

}

 

public static void finish(Object edgeEffect) {

((EdgeEffect) edgeEffect).finish();

}

 

public static boolean onPull(Object edgeEffect, float deltaDistance) {

((EdgeEffect) edgeEffect).onPull(deltaDistance);

return true;

}

 

public static boolean onRelease(Object edgeEffect) {

EdgeEffect eff = (EdgeEffect) edgeEffect;

eff.onRelease();

return eff.isFinished();

}

 

public static boolean onAbsorb(Object edgeEffect, int velocity) {

((EdgeEffect) edgeEffect).onAbsorb(velocity);

return true;

}

 

public static boolean draw(Object edgeEffect, Canvas canvas) {

return ((EdgeEffect) edgeEffect).draw(canvas);

}

}

 

à下面進入到EdgeEffect.java中吧à如果你有閑情逸致的話,那就看下他的代碼吧,都是這貨在搞鬼。

 

下面就說正經的內容了,看看我的解決方案:

主要是在自定義的OnPageChangeListener里面。

先定義一下:

private EdgeEffectCompat leftEdge;

private EdgeEffectCompat rightEdge;

然后是構造中,通過反射得到對象:

try {

    Field leftEdgeField = mViewPager.getClass().getDeclaredField("mLeftEdge");

    Field rightEdgeField = mViewPager.getClass().getDeclaredField("mRightEdge");

    

    Log.i("xinye", "=======leftEdgeField:" + leftEdgeField + ",rightEdgeField:" + rightEdgeField);

    if(leftEdgeField != null && rightEdgeField != null){

        

        leftEdgeField.setAccessible(true);

        rightEdgeField.setAccessible(true);

        

        leftEdge = (EdgeEffectCompat) leftEdgeField.get(mViewPager);

        rightEdge = (EdgeEffectCompat) rightEdgeField.get(mViewPager);

        Log.i("xinye", "=======OK啦,leftEdge:" + leftEdge + ",rightEdge:" + rightEdge);

    }

    

} catch (Exception e) {

    e.printStackTrace();

}

 

然后,就是最重要的了:

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels){

 

        if(leftEdge != null && rightEdge != null){

            leftEdge.finish();

            rightEdge.finish();

            leftEdge.setSize(0, 0);

            rightEdge.setSize(0, 0);

        }

 

好吧,完事了。做做看吧

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM