在没有质量损失的情况下放大Android中的imageview

时间:2014-11-12 13:30:28

标签: android xamarin imageview zoom

我需要捏缩放和拖动/平移图像,所以我实现了scaleimageview。 但是我放大的越多,图像越模糊。 我现在差不多3天寻找解决方案了。 我的代码看起来像这样(我使用Xamarin for Android):

using Android.Views;
using Android.Widget;

namespace test
{

public class ScaleImageViewGestureDetector : GestureDetector.SimpleOnGestureListener
{
    private readonly ScaleImageView m_ScaleImageView;
    public ScaleImageViewGestureDetector(ScaleImageView imageView)
    {
        m_ScaleImageView = imageView;
    }

    public override bool OnDown(MotionEvent e)
    {
        return true;
    }

    public override bool OnDoubleTap(MotionEvent e)
    {
        m_ScaleImageView.MaxZoomTo((int)e.GetX(), (int)e.GetY());
        m_ScaleImageView.Cutting();
        return true;
    }
}

public class ScaleImageView : ImageView, View.IOnTouchListener
{
    private Context m_Context;

    private float m_MaxScale = 2.0f;

    private Matrix m_Matrix;
    private float[] m_MatrixValues = new float[9];
    private int m_Width;
    private int m_Height;
    private int m_IntrinsicWidth;
    private int m_IntrinsicHeight;
    private float m_Scale;
    private float m_MinScale;
    private float m_PreviousDistance;
    private int m_PreviousMoveX;
    private int m_PreviousMoveY;
    private bool m_IsScaling;
    private GestureDetector m_GestureDetector;

    public ScaleImageView(Context context, IAttributeSet attrs) :
    base(context, attrs)
    {
        m_Context = context;
        Initialize();
    }

    public ScaleImageView(Context context, IAttributeSet attrs, int defStyle) :
    base(context, attrs, defStyle)
    {
        m_Context = context;
        Initialize();
    }

    public override void SetImageBitmap(Bitmap bm)
    {
        base.SetImageBitmap(bm);
        this.Initialize();
    }

    public override void SetImageResource(int resId)
    {
        base.SetImageResource(resId);
        this.Initialize();
    }


    private void Initialize()
    {
        this.SetScaleType(ScaleType.Matrix);
        m_Matrix = new Matrix();

        if (Drawable != null)
        {
            m_IntrinsicWidth = Drawable.IntrinsicWidth;
            m_IntrinsicHeight = Drawable.IntrinsicHeight;
            this.SetOnTouchListener(this);
        }

        m_GestureDetector = new GestureDetector(m_Context, new ScaleImageViewGestureDetector(this));
    }

    protected override bool SetFrame(int l, int t, int r, int b)//left top right bottom
    {
        m_Width = r - l;
        m_Height = b - t;

        Console.WriteLine ("test");
        Console.WriteLine (m_Width.ToString ());
        Console.WriteLine (m_Height.ToString ());

        m_Matrix.Reset();

        var r_norm = r - l;
        m_Scale = (float)r_norm / (float)m_IntrinsicWidth;

        ImageMatrix = m_Matrix;

        double height = Resources.DisplayMetrics.HeightPixels;
        double width = Resources.DisplayMetrics.WidthPixels;

        float scaleFactor = (float)(height/m_IntrinsicHeight);

        //don't take screen height, there's a tabbar on the bottom of the screen!
        m_Matrix.PostTranslate( (float) ((width-m_IntrinsicWidth)/2.00f),(float) ((m_Height-m_IntrinsicHeight)/2.00f)); 

        m_MinScale = scaleFactor;
        ZoomTo(m_Scale, m_Width / 2, m_Height / 2);
        Cutting();
        return base.SetFrame(l, t, r, b);
    }

    private float GetValue(Matrix matrix, int whichValue)
    {
        matrix.GetValues(m_MatrixValues);
        return m_MatrixValues[whichValue];
    }



    public float Scale
    {
        get { return this.GetValue(m_Matrix, Matrix.MscaleX); }
    }

    public float TranslateX
    {
        get { return this.GetValue(m_Matrix, Matrix.MtransX); }
    }

    public float TranslateY
    {
        get { return this.GetValue(m_Matrix, Matrix.MtransY); }
    }

    public void MaxZoomTo(int x, int y)
    {
        if (this.m_MinScale != this.Scale && (Scale - m_MinScale) > 0.1f)
        {
            var scale = m_MinScale / Scale;
            ZoomTo(scale, x, y);
        }
        else
        {
            var scale = m_MaxScale / Scale;
            ZoomTo(scale, x, y);
        }
    }

    public void ZoomTo(float scale, int x, int y)
    {
        if (Scale * scale < m_MinScale)
        {
            scale = m_MinScale / Scale;
        }
        else
        {
            if (scale >= 1 && Scale * scale > m_MaxScale)
            {
                scale = m_MaxScale / Scale;
            }
        }
        m_Matrix.PostScale(scale, scale);
        //move to center
        m_Matrix.PostTranslate(-(m_Width * scale - m_Width) / 2, -(m_Height * scale - m_Height) / 2);

        //move x and y distance
        m_Matrix.PostTranslate(-(x - (m_Width / 2)) * scale, 0);
        m_Matrix.PostTranslate(0, -(y - (m_Height / 2)) * scale);
        ImageMatrix = m_Matrix;
    }

    public void Cutting()
    {
        var width = (int)(m_IntrinsicWidth * Scale);
        var height = (int)(m_IntrinsicHeight * Scale);

        if (TranslateX < -(width - m_Width))
        {
            m_Matrix.PostTranslate(-(TranslateX + width - m_Width), 0);
        }

        if (TranslateX > 0)
        {
            m_Matrix.PostTranslate(-TranslateX, 0);
        }

        if (TranslateY < -(height - m_Height))
        {
            m_Matrix.PostTranslate(0, -(TranslateY + height - m_Height));
        }

        if (TranslateY > 0)
        {
            m_Matrix.PostTranslate(0, -TranslateY);
        }

        if (width < m_Width)
        {
            m_Matrix.PostTranslate((m_Width - width) / 2, 0);
        }

        if (height < m_Height)
        {
            m_Matrix.PostTranslate(0, (m_Height - height) / 2);
        }

        ImageMatrix = m_Matrix;
    }

    private float Distance(float x0, float x1, float y0, float y1)
    {
        var x = x0 - x1;
        var y = y0 - y1;
        return FloatMath.Sqrt(x * x + y * y);
    }

    private float DispDistance()
    {
        return FloatMath.Sqrt(m_Width * m_Width + m_Height * m_Height);
    }

    public override bool OnTouchEvent(MotionEvent e)
    {
        if (m_GestureDetector.OnTouchEvent(e))
        {
            m_PreviousMoveX = (int)e.GetX();
            m_PreviousMoveY = (int)e.GetY();
            return true;
        }

        var touchCount = e.PointerCount;
        switch (e.Action)
        {
        case MotionEventActions.Down:
        case MotionEventActions.Pointer1Down:
        case MotionEventActions.Pointer2Down:
            {
                if (touchCount >= 2)
                {
                    var distance = this.Distance(e.GetX(0), e.GetX(1), e.GetY(0), e.GetY(1));
                    m_PreviousDistance = distance;
                    m_IsScaling = true;
                }
            }
            break;

        case MotionEventActions.Move:
            {
                if (touchCount >= 2 && m_IsScaling)
                {
                    var distance = this.Distance(e.GetX(0), e.GetX(1), e.GetY(0), e.GetY(1));
                    var scale = (distance - m_PreviousDistance) / this.DispDistance();
                    m_PreviousDistance = distance;
                    scale += 1;
                    scale = scale * scale;
                    this.ZoomTo(scale, m_Width / 2, m_Height / 2);
                    this.Cutting();
                }
                else if (!m_IsScaling)
                {
                    var distanceX = m_PreviousMoveX - (int)e.GetX();
                    var distanceY = m_PreviousMoveY - (int)e.GetY();
                    m_PreviousMoveX = (int)e.GetX();
                    m_PreviousMoveY = (int)e.GetY();

                    m_Matrix.PostTranslate(-distanceX, -distanceY);
                    this.Cutting();
                }
            }
            break;
        case MotionEventActions.Up:
        case MotionEventActions.Pointer1Up:
        case MotionEventActions.Pointer2Up:
            {
                if (touchCount <= 1)
                {
                    m_IsScaling = false;
                }
            }
            break;
        }
        return true;
    }

    public bool OnTouch(View v, MotionEvent e)
    {
        return OnTouchEvent(e);
    }
}

}

0 个答案:

没有答案