Зум

Ответить
Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Зум

Сообщение Banhammer » 24 июн 2013, 17:31

как реализовать зум ImageView через нажатие?
я может идиот, но ей богу нигде не вижу ничего на эту тему)))
тоесть есть ImageView, в нём есть картинка из ресурсов, вешаем на компоненту обработчик нажатия, а что дальше?)
как я думаю, нужно баловаться с xml параметрами, но чтогдекогда, какой это даст результат, как себя это будет вести, нужно ли ложить ImageView в Scroll, или нет в этом необходимости... много вопросов, очень много.
Расскажи кто-нить опытный пожалуйста, дико интересно.
Или быть может есть какой-то стандартный класс для таких задач?
Какой способ лучше, с какой версии что будет работать и тд..

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Зум

Сообщение rezak90 » 24 июн 2013, 17:47

Вам какой зум нужен? если мультитач (ну когда пару пальцев и приближаем/увеличиваем) то это не проблема, то дам готовый класс.
R.id.team
Политика на форуме запрещена

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 24 июн 2013, 17:53

ну насколько я знаю, мультитач работает с определённой версии андроида(например на моём телефоне он есть, а на телефоне моей мадамы нету). как технология, мне это тоже интересно, но в данный момент не хочется лезть вперёд, поэтому интересуют больше махинации типа нажал->на 50% увеличилось изображение, нажал-> уменьшилось. пока что этого мне хватит)))
а вообще нужны любые зумы, статьи, книжки, топики, я бы всё почитал с удовольствием, но только по порядку: от элементарного к тяжёлому)

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Зум

Сообщение rezak90 » 24 июн 2013, 18:04

мультитач от версии не зависит, это может смартфон не поддерживает мультитач, но я таких не видел, если остались такие то это раритер)))
вся магия заключается в ScaleView:

Код: Выделить всё

public class ScaleView extends View {
	private static final int INVALID_POINTER_ID = -1;

	private Drawable mIcon;
	private float mPosX;
	private float mPosY;

	private float mLastTouchX;
	private float mLastTouchY;
	private int mActivePointerId = INVALID_POINTER_ID;

	private ScaleGestureDetector mScaleDetector;
	private float mScaleFactor = 1.f;
	private BitmapFactoryHack bfh = new BitmapFactoryHack(true);
	private static final String TAG = "ScaleView";
	private Context context;

	public ScaleView(Context context, String _path) {
		this(context, null, 0, _path);
		this.context = context;
	}

	public void clear() {
		bfh.freeAll();
	}

	public ScaleView(Context context, AttributeSet attrs, String _path) {
		this(context, attrs, 0, _path);
		this.context = context;
	}

	@SuppressWarnings("deprecation")
	public ScaleView(Context context, AttributeSet attrs, int defStyle,
			String path) {
		super(context, attrs, defStyle);
		this.context = context;
		try {
			mIcon = new BitmapDrawable(bfh.alloc(FileManager.decrypt(
					FileManager.getFullPathForFile(path, context), context),
					path));
		} catch (IOException e) {
			Log.d(TAG, "IOException");
		} catch(NullPointerException ex) {
			
		}
		if (mIcon == null) {
			Log.d(TAG, "mIcon is null");
			Toast.makeText(context, R.string.osi_outofmemoryerror,
					Toast.LENGTH_SHORT);
			return;
		}
		mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(),
				mIcon.getIntrinsicHeight());
		mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		try {
			mScaleDetector.onTouchEvent(ev);
			final int action = ev.getAction();
			switch (action & MotionEvent.ACTION_MASK) {
			case MotionEvent.ACTION_DOWN: {
				final float x = ev.getX();
				final float y = ev.getY();

				mLastTouchX = x;
				mLastTouchY = y;
				mActivePointerId = ev.getPointerId(0);
				break;
			}

			case MotionEvent.ACTION_MOVE: {
				final int pointerIndex = ev.findPointerIndex(mActivePointerId);
				final float x = ev.getX(pointerIndex);
				final float y = ev.getY(pointerIndex);
				if (!mScaleDetector.isInProgress()) {
					final float dx = x - mLastTouchX;
					final float dy = y - mLastTouchY;

					mPosX += dx;
					mPosY += dy;

					invalidate();
				}

				mLastTouchX = x;
				mLastTouchY = y;

				break;
			}

			case MotionEvent.ACTION_UP: {
				mActivePointerId = INVALID_POINTER_ID;
				break;
			}

			case MotionEvent.ACTION_CANCEL: {
				mActivePointerId = INVALID_POINTER_ID;
				break;
			}

			case MotionEvent.ACTION_POINTER_UP: {
				final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
				final int pointerId = ev.getPointerId(pointerIndex);
				if (pointerId == mActivePointerId) {
					final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
					mLastTouchX = ev.getX(newPointerIndex);
					mLastTouchY = ev.getY(newPointerIndex);
					mActivePointerId = ev.getPointerId(newPointerIndex);
				}
				break;
			}
			}
		} catch (NullPointerException e) {
			Log.d(TAG, "mIcon is null");
			Toast.makeText(context, R.string.osi_outofmemoryerror,
					Toast.LENGTH_SHORT);
			return true;
		}
		return true;
	}

	@Override
	public void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		try {
			canvas.save();
			canvas.translate(mPosX, mPosY);
			canvas.scale(mScaleFactor, mScaleFactor);
			mIcon.draw(canvas);
			canvas.restore();
		} catch (NullPointerException e) {
			Log.d(TAG, "mIcon is null");
			Toast.makeText(context, R.string.osi_outofmemoryerror,
					Toast.LENGTH_SHORT);
		}
	}

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {
		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			mScaleFactor *= detector.getScaleFactor();
			mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));

			invalidate();
			return true;
		}
	}
}
далее активити:

Код: Выделить всё

public class OSIActivity extends BaseActivity {

	public static final String F_PATH = "path";
	private ScaleView view;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}
	
	@Override
	protected void onResume() {
		String path = getIntent().getExtras().getString(F_PATH);
		view = new ScaleView(this, path);
		view.setLayoutParams(new ViewGroup.LayoutParams(
				ViewGroup.LayoutParams.MATCH_PARENT,
				ViewGroup.LayoutParams.MATCH_PARENT));
		setContentView(view);
		super.onResume();
	}

}
Класс BitmapFactoryHack:

Код: Выделить всё

public class BitmapFactoryHack
{
	private final VMRuntimeHack runtime = new VMRuntimeHack();
	private final boolean useHack;
	private Set<Bitmap> allocatedBitmaps = new HashSet<Bitmap>();
	private HashMap<String, SoftReference<Bitmap>> hackedBitmaps = new HashMap<String, SoftReference<Bitmap>>();

	public BitmapFactoryHack(boolean useHack)
	{
		this.useHack = useHack;
	}

	public Bitmap alloc(Bitmap bitmap, String key)
	{
		Bitmap bmp = bitmap;
		if (useHack)
		{
			if (!hackedBitmaps.containsKey(key))
			{
				runtime.trackFree(bmp.getRowBytes() * bmp.getHeight());
				hackedBitmaps.put(key, new SoftReference<Bitmap>(bmp));
			}
		}
		allocatedBitmaps.add(bmp);
		return bmp;
	}

	public int getCount()
	{
		return hackedBitmaps.size();
	}

	public void free(Bitmap bmp)
	{
		bmp.recycle();
		System.gc();
		System.gc();
		// if (hackedBitmaps.containsValue(bmp)) {
		runtime.trackAlloc(bmp.getRowBytes() * bmp.getHeight());
		hackedBitmaps.remove(bmp);
		// }

	}

	public void freeAll()
	{
		hackedBitmaps.clear();
		for (Bitmap bmp : new LinkedList<Bitmap>(allocatedBitmaps))
			free(bmp);
	}

	public Bitmap getBitmap(String key)
	{
		if (hackedBitmaps.containsKey(key))
		{
			return hackedBitmaps.get(key).get();
		}
		return null;
	}

	class VMRuntimeHack
	{
		private Object runtime = null;
		private Method trackAllocation = null;
		private Method trackFree = null;
		private static final String TAG = "VMRuntimeHack";

		public boolean trackAlloc(long size)
		{
			if (runtime == null)
				return false;
			try
			{
				Object res = trackAllocation.invoke(runtime, Long.valueOf(size));
				return (res instanceof Boolean) ? (Boolean) res : true;
			}
			catch (IllegalArgumentException e)
			{
				return false;
			}
			catch (IllegalAccessException e)
			{
				return false;
			}
			catch (InvocationTargetException e)
			{
				return false;
			}
		}

		public boolean trackFree(long size)
		{
			if (runtime == null)
				return false;
			try
			{
				Object res = trackFree.invoke(runtime, Long.valueOf(size));
				return (res instanceof Boolean) ? (Boolean) res : true;
			}
			catch (IllegalArgumentException e)
			{
				return false;
			}
			catch (IllegalAccessException e)
			{
				return false;
			}
			catch (InvocationTargetException e)
			{
				return false;
			}
		}

		public VMRuntimeHack()
		{
			boolean success = false;
			try
			{
				Class cl = Class.forName("dalvik.system.VMRuntime");
				Method getRt = cl.getMethod("getRuntime", new Class[0]);
				runtime = getRt.invoke(null, new Object[0]);
				trackAllocation = cl.getMethod("trackExternalAllocation", new Class[] { long.class });
				trackFree = cl.getMethod("trackExternalFree", new Class[] { long.class });
				success = true;
			}
			catch (ClassNotFoundException e)
			{
			}
			catch (SecurityException e)
			{
			}
			catch (NoSuchMethodException e)
			{
			}
			catch (IllegalArgumentException e)
			{
			}
			catch (IllegalAccessException e)
			{
			}
			catch (InvocationTargetException e)
			{
			}
			if (!success)
			{
				Log.e(TAG, "VMRuntime hack does not work!");
				runtime = null;
				trackAllocation = null;
				trackFree = null;
			}
		}
	}
}
Последний раз редактировалось rezak90 24 июн 2013, 18:30, всего редактировалось 1 раз.
R.id.team
Политика на форуме запрещена

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 24 июн 2013, 18:26

омг))
BitmapFactoryHack, не существует класс оО, он библиотечный?

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Зум

Сообщение KamiSempai » 24 июн 2013, 18:27

Для отлова момента зумирования можно использовать ScaleGestureDetector
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Зум

Сообщение rezak90 » 24 июн 2013, 18:28

KamiSempai писал(а):Для отлова момента зумирования можно использовать ScaleGestureDetector
сейчас да, но этот класс ScaleView я ещё год назад нашёл на гите))
R.id.team
Политика на форуме запрещена

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Зум

Сообщение rezak90 » 24 июн 2013, 18:30

Banhammer писал(а):омг))
BitmapFactoryHack, не существует класс оО, он библиотечный?
обновил
R.id.team
Политика на форуме запрещена

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 24 июн 2013, 19:32

так, немножко разобрался, пересмотрел кучу реализаций и тд, что сразу бросается в глаза, так это вот эта строчка
setContentView(view);
тоесть нет возможности просто взять ImageView и извращать его? нужно обязательно создавать свой View?
Последний раз редактировалось Banhammer 24 июн 2013, 20:43, всего редактировалось 1 раз.

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 24 июн 2013, 19:36

rezak90 писал(а):
Banhammer писал(а):омг))
BitmapFactoryHack, не существует класс оО, он библиотечный?
обновил
и FileManager тоже не определяется, он тоже не библиотечный?
нехилая такая реализация мультитач зума, аж 3 класса левых =(

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 25 июн 2013, 16:44

да ладно ребят, неужели никто не работал с зумом? или эта инфа засекречена в нашей стране?)

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Зум

Сообщение rezak90 » 25 июн 2013, 17:35

Banhammer писал(а):
rezak90 писал(а):
Banhammer писал(а):омг))
BitmapFactoryHack, не существует класс оО, он библиотечный?
обновил
и FileManager тоже не определяется, он тоже не библиотечный?
нехилая такая реализация мультитач зума, аж 3 класса левых =(
можно ж было догадаться что метод getFullPathForFile возвращает абсолютный путь к файлу и написать его самому:

Код: Выделить всё

public static String getFullPathForFile(String fileName, Context context)
	{
		if (context.getExternalFilesDir(null) != null)
		{
			if (fileName == null)
			{
				return getAppFolderSD(context).toString();
			}
			return String.format("%s/%s", getAppFolderSD(context).toString(), fileName);
		}
		else
		{
			if (fileName == null)
			{
				return context.getExternalFilesDir(null).toString();
			}
			return new File(context.getExternalFilesDir(null), fileName).getAbsolutePath();
		}
	}
private static File getAppFolderSD(Context context)
	{
		File file = context.getExternalFilesDir(null);
		if (file == null)
		{
			file = context.getFilesDir();
		}
		if (!file.exists())
		{
			file.mkdir();
		}

		return file;
	}
он Вам в принципи и не нужен.
R.id.team
Политика на форуме запрещена

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 25 июн 2013, 19:10

вот нашёл интересную реализацию, как раз подходящую под абсолютно все мои нужды

Код: Выделить всё

imageDetail.setOnTouchListener(new View.OnTouchListener() {

			private String TAG="lal";

			@Override
			public boolean onTouch(View v, MotionEvent event) {

				ImageView view = (ImageView) v;
				System.out.println("matrix=" + savedMatrix.toString());
				switch (event.getAction() & MotionEvent.ACTION_MASK) {
				case MotionEvent.ACTION_DOWN:

					savedMatrix.set(matrix);
					startPoint.set(event.getX(), event.getY());
					mode = DRAG;
					break;

				case MotionEvent.ACTION_POINTER_DOWN:
Log.w(TAG, "CASE: ACTION POINTER DAWN");
					oldDist = spacing(event);

					if (oldDist > 10f) {
						savedMatrix.set(matrix);
						midPoint(midPoint, event);
						mode = ZOOM;
					}
					break;

				case MotionEvent.ACTION_UP:

				case MotionEvent.ACTION_POINTER_UP:
					mode = NONE;
					Log.w(TAG, "CASE: ACTION POINTER UP");
					break;

				case MotionEvent.ACTION_MOVE:
					if (mode == DRAG) {
						matrix.set(savedMatrix);
						matrix.postTranslate(event.getX() - startPoint.x,
								event.getY() - startPoint.y);
					} else if (mode == ZOOM) {
						float newDist = spacing(event);
						if (newDist > 10f) {
							matrix.set(savedMatrix);
							float scale = newDist / oldDist;
							matrix.postScale(scale, scale, midPoint.x, midPoint.y);
						}
					}
					break;

				}
				view.setImageMatrix(matrix);

				return true;
			}

			@SuppressLint("FloatMath")
			private float spacing(MotionEvent event) {
				float x = event.getX(0) - event.getX(1);
				float y = event.getY(0) - event.getY(1);
				return FloatMath.sqrt(x * x + y * y);
			}

			private void midPoint(PointF point, MotionEvent event) {
				float x = event.getX(0) + event.getX(1);
				float y = event.getY(0) + event.getY(1);
				point.set(x / 2, y / 2);
			}
		});
но тут есть минус, изображение может вылазить за экран, тоесть его можно *выкинуть* из поля действия пользователя
есть возможность это решить в данной реализации?

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Зум

Сообщение rezak90 » 25 июн 2013, 19:52

я нормальный пример привёл, чем не нравится?
R.id.team
Политика на форуме запрещена

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 25 июн 2013, 20:17

меня расстраивает реализация через новый view)))) для меня в данный момент: момент, когда уже написано приложение, очень подходит именно переопределение OnTouchListener.
вставил кусок кода, ура, кидай друзьям все пользуются счастливые)

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Зум

Сообщение rezak90 » 25 июн 2013, 22:51

Banhammer писал(а):меня расстраивает реализация через новый view)))) для меня в данный момент: момент, когда уже написано приложение, очень подходит именно переопределение OnTouchListener.
вставил кусок кода, ура, кидай друзьям все пользуются счастливые)
я вижу на сколько такой код удобен))) попробуйте в ддмс посмотреть объёмы памяти при зуме.
R.id.team
Политика на форуме запрещена

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 25 июн 2013, 23:01

ну если ты про то, что зум ничерта не контролируемый и займёт просто уйму памяти, то да, тут есть грех)))
по интеграции в код, это удобно, всунул и збс, а в твоём варианте ещё пути какие-то, всё сложно и опасно))) я остерегаюсь таких моментов в начале своего пути))

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Зум

Сообщение rezak90 » 25 июн 2013, 23:40

Banhammer писал(а):ну если ты про то, что зум ничерта не контролируемый и займёт просто уйму памяти, то да, тут есть грех)))
по интеграции в код, это удобно, всунул и збс, а в твоём варианте ещё пути какие-то, всё сложно и опасно))) я остерегаюсь таких моментов в начале своего пути))
те пути что у меня, то я просто со своего приложения копировал, там так дела обстоят... а на счёт памяти советую протестировать что бы не вылезло боком потом
R.id.team
Политика на форуме запрещена

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 25 июн 2013, 23:53

rezak90 писал(а):
Banhammer писал(а):ну если ты про то, что зум ничерта не контролируемый и займёт просто уйму памяти, то да, тут есть грех)))
по интеграции в код, это удобно, всунул и збс, а в твоём варианте ещё пути какие-то, всё сложно и опасно))) я остерегаюсь таких моментов в начале своего пути))
те пути что у меня, то я просто со своего приложения копировал, там так дела обстоят... а на счёт памяти советую протестировать что бы не вылезло боком потом
ну я понимаю все замуты с памятью и слёзками, связанными с ними, но что поделать?) тут покрайней мере я понимаю что происходит мало-мальски, а в твоём варианте всё просто дико не понятно, но понятно одно: интегрировать его в мой код- гигантская проблема(

Banhammer
Сообщения: 32
Зарегистрирован: 24 июн 2013, 17:09

Re: Зум

Сообщение Banhammer » 26 июн 2013, 01:23

так от чего можно отталкиваться, чтобы не вылезала картинка из компоненты?

Ответить