zoukankan      html  css  js  c++  java
  • 禁用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);

            }

    好吧,完事了。做做看吧

  • 相关阅读:
    Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第四部分(Page 9)
    Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第一部分(Page 6)
    Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第二部分(Page 7)
    Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第三部分(Page 8)
    Django 2.0.1 官方文档翻译: 如何安装 django (Page 17)
    Django 2.0.1 官方文档翻译: 文档目录 (Page 1)
    Django 2.0.1 官方文档翻译: 快速安装向导 (Page5)
    如何画流程图
    centos7.x firewall简单使用
    cetos6配置用msmtp和mutt发邮件(阿里云)
  • 原文地址:https://www.cnblogs.com/xinye/p/3142704.html
Copyright © 2011-2022 走看看