Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Scaleable / zoomable imageview for Xamarin Android
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Android.Content;
using Android.Graphics;
using Android.Util;
using Android.Views;
using Android.Widget;
namespace Droid
{
public class ScaleImageViewGestureDetector : GestureDetector.SimpleOnGestureListener
{
readonly ScaleImageView _scaleImageView;
public ScaleImageViewGestureDetector(ScaleImageView scaleImageView)
{
_scaleImageView = scaleImageView;
}
public override bool OnDown(MotionEvent e)
{
return true;
}
public override bool OnDoubleTap(MotionEvent e)
{
_scaleImageView.MaxZoomTo((int)e.GetX(), (int)e.GetY());
_scaleImageView.Cutting();
return true;
}
}
public class ScaleImageView : ImageView, View.IOnTouchListener, INotifyPropertyChanged
{
Matrix _matrix;
float[] _matrixValues = new float[9];
int _width;
int _height;
int _intrinsicWidth;
int _intrinsicHeight;
float _scale;
float _minScale;
float _previousDistance;
int _previousMoveX;
int _previousMoveY;
bool _isScaling;
GestureDetector _gestureDetector;
public float MaxScale { get; set; } = 2.0f;
bool _isScaled;
public bool IsScaled
{
get
{
return _isScaled;
}
private set
{
_isScaled = value;
OnPropertyChanged();
}
}
public float Scale
{
get { return GetValue(_matrix, Matrix.MscaleX); }
}
public float TranslateX
{
get { return GetValue(_matrix, Matrix.MtransX); }
}
public float TranslateY
{
get { return GetValue(_matrix, Matrix.MtransY); }
}
public event PropertyChangedEventHandler PropertyChanged;
public ScaleImageView(Context context, IAttributeSet attrs) :
base(context, attrs)
{
Initialize();
}
public ScaleImageView(Context context, IAttributeSet attrs, int defStyle) :
base(context, attrs, defStyle)
{
Initialize();
}
public override void SetImageBitmap(Bitmap bm)
{
base.SetImageBitmap(bm);
Initialize();
}
public override void SetImageResource(int resId)
{
base.SetImageResource(resId);
Initialize();
}
void Initialize()
{
SetScaleType(ScaleType.Matrix);
_matrix = new Matrix();
if (Drawable != null)
{
_intrinsicWidth = Drawable.IntrinsicWidth;
_intrinsicHeight = Drawable.IntrinsicHeight;
SetOnTouchListener(this);
}
_gestureDetector = new GestureDetector(Context, new ScaleImageViewGestureDetector(this));
}
protected override bool SetFrame(int l, int t, int r, int b)
{
_width = r - l;
_height = b - t;
_matrix.Reset();
var r_norm = r - l;
_scale = (float)r_norm / (float)_intrinsicWidth;
var paddingHeight = 0;
var paddingWidth = 0;
if (_scale * _intrinsicHeight > _height)
{
_scale = (float)_height / (float)_intrinsicHeight;
_matrix.PostScale(_scale, _scale);
paddingWidth = (r - _width) / 2;
}
else
{
_matrix.PostScale(_scale, _scale);
paddingHeight = (b - _height) / 2;
}
_matrix.PostTranslate(paddingWidth, paddingHeight);
ImageMatrix = _matrix;
_minScale = _scale;
Cutting();
return base.SetFrame(l, t, r, b);
}
float GetValue(Matrix matrix, int whichValue)
{
matrix.GetValues(_matrixValues);
return _matrixValues[whichValue];
}
public void MaxZoomTo(int x, int y)
{
if (_minScale != Scale && (Scale - _minScale) > 0.1f)
{
var scale = _minScale / Scale;
ZoomTo(scale, x, y);
}
else
{
var scale = MaxScale / Scale;
ZoomTo(scale, x, y);
}
}
public void ZoomTo(float scale, int x, int y)
{
if (Scale * scale < _minScale)
{
scale = _minScale / Scale;
}
else
{
if (scale >= 1 && Scale * scale > MaxScale)
{
scale = MaxScale / Scale;
}
}
_matrix.PostScale(scale, scale);
//move to center
_matrix.PostTranslate(-(_width * scale - _width) / 2, -(_height * scale - _height) / 2);
//move x and y distance
_matrix.PostTranslate(-(x - (_width / 2)) * scale, 0);
_matrix.PostTranslate(0, -(y - (_height / 2)) * scale);
ImageMatrix = _matrix;
}
public void Cutting()
{
var width = (int)(_intrinsicWidth * Scale);
var height = (int)(_intrinsicHeight * Scale);
if (TranslateX < -(width - _width))
{
_matrix.PostTranslate(-(TranslateX + width - _width), 0);
}
if (TranslateX > 0)
{
_matrix.PostTranslate(-TranslateX, 0);
}
if (TranslateY < -(height - _height))
{
_matrix.PostTranslate(0, -(TranslateY + height - _height));
}
if (TranslateY > 0)
{
_matrix.PostTranslate(0, -TranslateY);
}
if (width < _width)
{
_matrix.PostTranslate((_width - width) / 2, 0);
}
if (height < _height)
{
_matrix.PostTranslate(0, (_height - height) / 2);
}
ImageMatrix = _matrix;
IsScaled = Scale > _minScale;
}
float Distance(float x0, float x1, float y0, float y1)
{
var x = x0 - x1;
var y = y0 - y1;
return (float)Math.Sqrt(x * x + y * y);
}
float DispDistance()
{
return (float)Math.Sqrt(_width * _width + _height * _height);
}
public override bool OnTouchEvent(MotionEvent e)
{
if (_gestureDetector.OnTouchEvent(e))
{
_previousMoveX = (int)e.GetX();
_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 = Distance(e.GetX(0), e.GetX(1), e.GetY(0), e.GetY(1));
_previousDistance = distance;
_isScaling = true;
}
}
break;
case MotionEventActions.Move:
{
if (touchCount >= 2 && _isScaling)
{
var distance = Distance(e.GetX(0), e.GetX(1), e.GetY(0), e.GetY(1));
var scale = (distance - _previousDistance) / DispDistance();
_previousDistance = distance;
scale += 1;
scale = scale * scale;
ZoomTo(scale, _width / 2, _height / 2);
Cutting();
}
else if (!_isScaling)
{
var distanceX = _previousMoveX - (int)e.GetX();
var distanceY = _previousMoveY - (int)e.GetY();
_previousMoveX = (int)e.GetX();
_previousMoveY = (int)e.GetY();
_matrix.PostTranslate(-distanceX, -distanceY);
Cutting();
}
}
break;
case MotionEventActions.Up:
case MotionEventActions.Pointer1Up:
case MotionEventActions.Pointer2Up:
{
if (touchCount <= 1)
{
_isScaling = false;
}
}
break;
}
return true;
}
public bool OnTouch(View v, MotionEvent e)
{
return OnTouchEvent(e);
}
public void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
@dehghani-mehdi

This comment has been minimized.

Copy link

dehghani-mehdi commented Jun 23, 2018

Doesn't work here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.