В двух словах уточним, какое поведение элемента интерфейса мы хотим получить. Есть пара белых ImageView и один синий прямоугольник. Та из белых картинок, которой мы коснулись будет следовать за пальцем, пока мы её не отпустим. Если мы отпустим её над синим прямоугольником, прямоугольник станет красным, и картинка останется на месте. Если за пределами - картинка вернётся на исходную позицию.
Основная наша цель - сделать всё максимально просто. Кроме Layout-a, описывающего начальное состояние интерфейса, мы напишем всего один класс в сотню строк кода. Итак приступим.
Становимся в исходное положение
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <ImageView android:id="@+id/ImgDrop" android:layout_width="60dp" android:layout_height="60dp" android:layout_alignParentTop="true" android:layout_centerInParent="true" android:layout_marginTop="50dp" android:background="#0000ff"> </ImageView> <ImageView android:id="@+id/img" android:layout_width="60dp" android:layout_height="60dp" android:layout_alignParentBottom="true" android:src="@android:drawable/alert_light_frame"> </ImageView> <ImageView android:id="@+id/img2" android:layout_width="60dp" android:layout_height="60dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:src="@android:drawable/alert_light_frame"> </ImageView> </RelativeLayout>
Как я и описывал в условии задачи: тут синий прямоугольник и две картинки в RelativeLayout-е. Ничего особенного.
Двигаемся
Вот и наши 100 строк кода:
import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.widget.ImageView; import android.widget.RelativeLayout; public class MyActivity extends Activity implements OnTouchListener { private View selected_item = null; private int offset_x = 0; private int offset_y = 0; Boolean touchFlag = false; boolean dropFlag = false; LayoutParams imageParams; ImageView imageDrop, image1, image2; int eX, eY; int topY, leftX, rightX, bottomY; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.main); View root = findViewById(android.R.id.content).getRootView(); imageDrop = (ImageView) findViewById(R.id.ImgDrop); image1 = (ImageView) findViewById(R.id.img); image2 = (ImageView) findViewById(R.id.img2); image1.setOnTouchListener(this); image2.setOnTouchListener(this); root.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { if (touchFlag) { System.err.println("Display If Part ::->" + touchFlag); switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: topY = imageDrop.getTop(); leftX = imageDrop.getLeft(); rightX = imageDrop.getRight(); bottomY = imageDrop.getBottom(); break; case MotionEvent.ACTION_MOVE: eX = (int) event.getX(); eY = (int) event.getY(); int x = (int) event.getX() - offset_x; int y = (int) event.getY() - offset_y; int w = getWindowManager().getDefaultDisplay().getWidth() - 50; int h = getWindowManager().getDefaultDisplay().getHeight() - 10; if (x > w) x = w; if (y > h) y = h; RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(new ViewGroup.MarginLayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT)); lp.setMargins(x, y, 0, 0); if (eX > leftX && eX < rightX && eY > topY && eY < bottomY) { imageDrop.setBackgroundColor(Color.RED); selected_item.bringToFront(); dropFlag = true; } else { imageDrop.setBackgroundColor(Color.BLUE); } selected_item.setLayoutParams(lp); break; case MotionEvent.ACTION_UP: touchFlag = false; if (dropFlag) { dropFlag = false; } else { selected_item.setLayoutParams(imageParams); } break; default: break; } } return true; } }); } public boolean onTouch(View v, MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: touchFlag = true; offset_x = (int) event.getX(); offset_y = (int) event.getY(); selected_item = v; imageParams = v.getLayoutParams(); break; case MotionEvent.ACTION_UP: selected_item = null; touchFlag = false; break; default: break; } return false; } }
Посмотрим на наш код внимательнее. Вся логика реализована тут с помощью двух listener-ов. Первый OnTouchListener, метод onTouch которого реализует непосредственно наше Activity мы навешиваем на "подвижные" картинки. Задача, которую мы тут решаем - определить какая из картинок под пальцем, сохранить её начальные параметры расположения на случай, если нужно будет вернуться и установить флаг начала перемещения.
Второй OnTouchListener вешаем на самый верхний элемент иерархии View нашего Activity. Он определяет координаты "цели", перемещает картинку и проверяет, не попали ли мы уже в цель.
Большущее спасибище!!! Как раз искал подобный пример.
ОтветитьУдалитьТеперь осталось разобраться. Вы не пишите программ на заказ? Мне нужно типа мозаики. Так как у вас, только передвигать 3-5 кусочков и после того, как они попали на место, то делать запрет на Drag and Drop.
Если фрилансите, то пож, напишите мне serge_mikhailov##mail.ru
@android:drawable/alert_light_frame что особенного в этой картинке. По какой причине любые другие при перетаскивании изчезают?
ОтветитьУдалитьСпасибо за пример. У меня такое реализовано, только на JavaScript. Идём дальше пытаемся такое создать дя Android: http://zxworld.h19.ru/Ninephp.php
ОтветитьУдалитьСпасибо Вам большое, Вы так облегчили мне сейчас работу над магистерской!
ОтветитьУдалить