Android Gallery画廊 兼容4.0以上版本

来源:互联网 发布:java实现微信发送消息 编辑:程序博客网 时间:2024/05/07 12:25

最近在做Gallery画廊效果时,搜索大量资料,发现很多博主都是2012年写的文章。对于现在的sdk版本,发现拿过来都没有用,效果变形:



非常遗憾,中间的图变形了,或者说没有把转角恢复。

查阅了大量资料后,发现,


4.0以下的版本,调用的是下面的方法:

    @Override    protected boolean getChildStaticTransformation(View child, Transformation t) {        mMatrix = t.getMatrix();        if (android.os.Build.VERSION.SDK_INT > 15) {            return false;        } else {       <span style="white-space:pre"></span>//操作代码       }}

4.0以上版本,调用的是下面的方法:


    /**     * 核心方法     * @param canvas     * @param child     * @param drawingTime     * @return     */    @Override    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {        boolean ret;        //Android SDK 4.1        if (android.os.Build.VERSION.SDK_INT > 15) {            //操作代码        } else {            ret = super.drawChild(canvas, child, drawingTime);        }        return ret;    }


修改后兼容4.0以上版本得完整代码:

package com.znke.tv3_test.widgets;import android.content.Context;import android.graphics.Camera;import android.graphics.Canvas;import android.graphics.Matrix;import android.util.AttributeSet;import android.view.View;import android.view.animation.Transformation;import android.widget.Gallery;/** * 兼容4.0以上版本 */@SuppressWarnings("deprecation")public class CommonGallery extends Gallery {    private Camera mCamera;//相机类    private int mGalleryCenterX;//gallery容器的中心点位置    private Matrix mMatrix;    private int mMaxRotationAngle = 60;//最大转动角度    private boolean isNeedScrollY = true;//是否需要y轴角度旋转    private float xOffset = 80.0f;    private float yOffset = 70.0f;    private float zOffset = 50.0f;    /**     * 设置特定的参数     * @param xOffset x轴偏移量     * @param yOffset y轴偏移量     * @param zOffset z轴偏移量     * @param isNeedScrollY 是否需要两侧的图片旋转     * @param mMaxRotationAngle 两侧图片旋转的最大角度     */    public void setGalleryData(float xOffset,float yOffset,float zOffset,boolean isNeedScrollY,int mMaxRotationAngle){        setxOffset(xOffset);        setyOffset(yOffset);        setzOffset(zOffset);        setNeedScrollY(isNeedScrollY);        setmMaxRotationAngle(mMaxRotationAngle);    }    public void setmMaxRotationAngle(int mMaxRotationAngle) {        this.mMaxRotationAngle = mMaxRotationAngle;    }    public void setNeedScrollY(boolean needScrollY) {        isNeedScrollY = needScrollY;    }    public void setxOffset(float xOffset) {        this.xOffset = xOffset;    }    public void setyOffset(float yOffset) {        this.yOffset = yOffset;    }    public void setzOffset(float zOffset) {        this.zOffset = zOffset;    }    public CommonGallery(Context context) {        this(context, null, 0);    }    public CommonGallery(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public CommonGallery(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init(context, attrs);    }    private void init(Context context, AttributeSet attrs) {        //支持转换 ,执行getChildStaticTransformation方法        this.setStaticTransformationsEnabled(true);        this.setChildrenDrawingOrderEnabled(true);        mCamera = new Camera();    }    @Override    protected int getChildDrawingOrder(int childCount, int i) {        // Current selected index.        int selectedIndex = getSelectedItemPosition() - getFirstVisiblePosition();        if (selectedIndex < 0) {            return i;        }        if (i < selectedIndex) {            return i;        } else if (i >= selectedIndex) {            return childCount - 1 - i + selectedIndex;        } else {            return i;        }    }    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        mGalleryCenterX = getGalleryCenterX();        super.onSizeChanged(w, h, oldw, oldh);    }    //获取父控件中心点 X 的位置    protected int getGalleryCenterX() {        // + 比 >> 优先级高, x>>1等于x/2,效率高        return ((getWidth() - getPaddingLeft() - getPaddingRight()) >> 1) + getPaddingLeft();    }    //获取 child 中心点 X 的位置    protected int getChildCenterX(View child) {        // + 比 >> 优先级高        return (child.getWidth() >> 1) + child.getLeft();    }    //计算 child 偏离 父控件中心的 offset 值, -1 <= offset <= 1    protected float calculateOffsetOfCenter(View view) {        final int pCenter = getGalleryCenterX();        final int cCenter = getChildCenterX(view);        float offset = (cCenter - pCenter) / (pCenter * 1.0f);        //下面两步操作处理,把offset拉回到[-1,1]之间,防止越界        offset = Math.min(offset, 1.0f);//当超出1时,取1        offset = Math.max(offset, -1.0f);//当小于-1时,取-1        return offset;    }    /**     * 计算该view对应的角度     *     * @param child     * @return     */    private int calculateAngle(View child) {        int rotateAngle = 0;        //获取child的中心点        int childCenterX = getChildCenterX(child);        //如果当前child不在中心点,计算出对应的偏移的角度        if (childCenterX != mGalleryCenterX) {            // 两个中心点距离            int distance = mGalleryCenterX - childCenterX;            float percent = distance * 1.0f / child.getWidth();            rotateAngle = (int) (percent * mMaxRotationAngle);// 得到旋转的角度            // 因为distance有可能大于图片的宽度,所以得到角度有可能大于最大的角度            if (Math.abs(rotateAngle) > mMaxRotationAngle) {                rotateAngle = rotateAngle > 0 ? mMaxRotationAngle : -mMaxRotationAngle;            }        }        return rotateAngle;    }    /**     * 核心方法     * @param canvas     * @param child     * @param drawingTime     * @return     */    @Override    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {        boolean ret;        //Android SDK 4.1        if (android.os.Build.VERSION.SDK_INT > 15) {            //计算child与中心点的偏移量            final float offset = calculateOffsetOfCenter(child);            transformImageBitmap(child,offset);            child.setAlpha(1 - Math.abs(offset));            final int saveCount = canvas.save();            canvas.concat(mMatrix);            ret = super.drawChild(canvas, child, drawingTime);            canvas.restoreToCount(saveCount);        } else {            ret = super.drawChild(canvas, child, drawingTime);        }        return ret;    }    @Override    protected boolean getChildStaticTransformation(View child, Transformation t) {        mMatrix = t.getMatrix();        if (android.os.Build.VERSION.SDK_INT > 15) {            return false;        } else {            /**             * 兼容老版本,VERSION <= 15 才执行             */            //设置变化之前,要把上面的一个动画清除            t.clear();            //设置变化的效果为矩阵类型            t.setTransformationType(Transformation.TYPE_MATRIX);            //计算child与中心点的偏移量            final float offset = calculateOffsetOfCenter(child);            transformImageBitmap(child,offset);            //设置 alpha 变换            t.setAlpha(1 - Math.abs(offset));            return true;        }    }    /**     * 图像变换     * @param child     * @param offset     */    private void transformImageBitmap(View child,float offset){        //获取child的宽高的一半        final int halfWidth = getChildCenterX(child);        final int halfHeight = child.getMeasuredHeight() >> 1;        mCamera.save();        if(isNeedScrollY){            //是否需要角度旋转            if (halfWidth == mGalleryCenterX) {                //正中间的childView                mCamera.rotateY(0);            } else {                //两侧的childView                int rotateAngle = calculateAngle(child);                mCamera.rotateY(rotateAngle);            }        }        // 平移 X、Y、Z 轴已达到立体效果        mCamera.translate(-offset * xOffset, yOffset, Math.abs(offset) * zOffset);        //也可设置旋转效果        mCamera.getMatrix(mMatrix);        //以 child 的中心点变换        mMatrix.preTranslate(-halfWidth, -halfHeight);        mMatrix.postTranslate(halfWidth, halfHeight);        mCamera.restore();    }}


需要说明的是:

1、有的需求对两侧图片的要求是不需要转角,

2、有的对中间图片的大小有要求

3、有的对旁边图片的距离和层叠效果有要求


其实无非就是修改最大转角、是否需要转角、x轴偏移、y轴偏移、z轴偏移等5个参数的修改,故我提供方法:

    /**     * 设置特定的参数     * @param xOffset x轴偏移量     * @param yOffset y轴偏移量     * @param zOffset z轴偏移量     * @param isNeedScrollY 是否需要两侧的图片旋转     * @param mMaxRotationAngle 两侧图片旋转的最大角度     */    public void setGalleryData(float xOffset,float yOffset,float zOffset,boolean isNeedScrollY,int mMaxRotationAngle){        setxOffset(xOffset);        setyOffset(yOffset);        setzOffset(zOffset);        setNeedScrollY(isNeedScrollY);        setmMaxRotationAngle(mMaxRotationAngle);    }

其他的逻辑代码都是通用的,根据你自己的需求,只需要设置好这5个参数就可以了。








5 0
原创粉丝点击