Drag-and-drop adalah fitur umum dalam desain UI(User Interface) Memungkinkan pengguna untuk berinteraksi dengan aplikasi Anda. Unity saat ini mendukung tiga sistem UI. More info
Lihat di Glossary. Anda dapat menggunakan UI Toolkit untuk membuat UI drag-and-drop di dalam jendela editor kustom atau dalam aplikasi yang dibangun oleh Unity. Contoh ini menunjukkan cara membuat UI drag-and-drop di dalam jendela editor kustom.
Contoh menambahkan beberapa slot dan satu objek di jendela editor kustom. Anda dapat menyeret objek ke dalam slot apa pun, seperti yang ditunjukkan di bawah ini:
Anda dapat menemukan file yang lengkap yang contoh ini menciptakan di Repositori GitHub ini.
Ini adalah contoh canggih untuk pengembang yang akrab dengan Editor Unity, UI Toolkit, dan C # scripting. Disarankan bahwa Anda memiliki pemahaman dasar tentang konsep berikut:
Untuk memulai, buat jendela editor kustom untuk menahan UI drag-and-drop Anda.
Assets
yang disebut DragAndDrop
untuk menyimpan semua file Anda.DragAndDrop
, klik kanan dan pilih Create > UI Toolkit > Editor Window.DragAndDropWindow
.DragAndDropWindow.cs
dan ubah nama menu dan judul jendela ke Drag And Drop
, dan lepaskan kode untuk label default, untuk membuat UI lebih ramah pengguna.Anda selesai DragAndDropWindow.cs
harus terlihat seperti berikut:
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
public class DragAndDropWindow : EditorWindow
{
[MenuItem("Window/UI Toolkit/Drag And Drop")]
public static void ShowExample()
{
DragAndDropWindow wnd = GetWindow<DragAndDropWindow>();
wnd.titleContent = new GUIContent("Drag And Drop");
}
public void CreateGUI()
{
// Each editor window contains a root VisualElement object
VisualElement root = rootVisualElement;
// Import UXML
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Drag and Drop/DragAndDropWindow.uxml");
VisualElement labelFromUXML = visualTree.Instantiate();
root.Add(labelFromUXML);
// A stylesheet can be added to a VisualElement.
// The style will be applied to the VisualElement and all of its children.
var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Drag and Drop/DragAndDropWindow.uss");
}
}
Selanjutnya, tambahkan kontrol UI ke jendela kustom Anda.
Dalam folder DragAndDrop
, klik dua DragAndDropWindow.uxml
untuk membuka UI Builder.
Pada StyleSheet, klik Add Existing USS dan pilih DragAndDropWindow.uss
.
Tambahkan kontrol UI VisualElement
berikut:
slots
dengan dua anak bernama slot_row1
dan slot_row2
. Setiap baris harus memiliki dua anak bernama slot1
dan slot2
.object
pada tingkat yang sama dengan slots
. object
harus datang setelah slots
di Hierarchy.Gaya kontrol UI sebagai berikut:
slot1
dan slot2
, gaya mereka sebagai kotak 80px X 80px dengan warna latar belakang putih dan sudut bulat. Menyiapkan slot sebagai dua baris dengan dua slot di setiap baris.object
, gaya itu sebagai titik bulat 50px X 50px dengan warna latar belakang hitam.
Untuk instruksi tentang cara menambahkan dan gaya UI kontrol, lihat Pembuat UI.
Anda selesai DragAndDropWindow.uxml
harus terlihat seperti berikut:
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<Style src="project://database/Assets/DragAndDrop/DragAndDropWindow.uss?fileID=7433441132597879392&guid=3d86870c8637c4a3c979a8b4fe0cba4c&type=3#DragAndDrop" />
<ui:VisualElement name="slots">
<ui:VisualElement name="slot_row1" class="slot_row">
<ui:VisualElement name="slot1" class="slot" />
<ui:VisualElement name="slot2" class="slot" />
</ui:VisualElement>
<ui:VisualElement name="slot_row2" class="slot_row">
<ui:VisualElement name="slot1" class="slot" />
<ui:VisualElement name="slot2" class="slot" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="object" class="object" />
</ui:UXML>
Anda selesai DragAndDropWindow.uss
harus terlihat seperti berikut:
.slot {
width: 80px;
height: 80px;
margin: 5px;
background-color: rgb(255, 255, 255);
border-top-radius: 10px;
}
.slot_row {
flex-direction: row;
}
.object {
width: 50px;
height: 50px;
position: absolute;
left: 10px;
top: 10px;
border-radius: 30px;
background-color: rgb(0, 0, 0);
}
Untuk menentukan perilaku drag-and-drop, memperpanjang kelas PointerManipulator
dan menentukan logika.
Dalam folder DragAndDrop
, buat file C# lain yang disebut DragAndDropManipulator.cs
.
Buka DragAndDropManipulator.cs
.
Tambahkan deklarasi using UnityEngine.UIElements;
.
Membuat kelas DragAndDropManipulator
memperpanjang PointerManipulator
daripada MonoBehaviour
, dan lakukan berikut:
RegisterCallbacksOnTarget()
untuk mendaftarkan semua callback yang diperlukanUnregisterCallbacksOnTarget()
untuk tidak ada penelepon yang Meme ittarget
dan menyimpan referensi ke akar pohon visualTulis empat metode yang bertindak sebagai callback untuk PointerDownEvent
s, PointerMoveEvent
s, PointerUpEvent
s, dan PointerCaptureOutEvent
s:
PointerDownHandler()
: Menyimpan posisi awal target
dan pointer, membuat target
menangkap pointer, dan menunjukkan bahwa seret sekarang dalam kemajuan.PointerMoveHandler()
: Periksa apakah seret dalam kemajuan dan apakah target
telah menangkap pointer. Jika keduanya benar, menghitung posisi baru untuk target
dalam batas jendela.PointerUpHandler()
: Periksa apakah seret dalam kemajuan dan apakah target
telah menangkap pointer. Jika keduanya benar, membuat target
melepaskan pointer.PointerCaptureOutHandler()
: Cek apakah seret sedang berlangsung. Jika benar, pertanyaan akar pohon visual untuk menemukan semua slot, memutuskan slot mana adalah yang paling dekat yang tumpang tindih target
, dan menetapkan posisi target
sehingga beristirahat di atas slot itu. Mengatur posisi target
kembali ke posisi aslinya jika tidak ada slot yang tumpang tindih.Pada RegisterCallbacksOnTarget()
, daftarkan empat callback ini pada target
.
Pada UnregisterCallbacksOnTarget()
, un-register ini empat callback dari target
.
Anda selesai DragAndDropManipulator.cs
harus terlihat seperti berikut:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class DragAndDropManipulator : PointerManipulator
{
public DragAndDropManipulator(VisualElement target)
{
this.target = target;
root = target.parent;
}
protected override void RegisterCallbacksOnTarget()
{
target.RegisterCallback<PointerDownEvent>(PointerDownHandler);
target.RegisterCallback<PointerMoveEvent>(PointerMoveHandler);
target.RegisterCallback<PointerUpEvent>(PointerUpHandler);
target.RegisterCallback<PointerCaptureOutEvent>(PointerCaptureOutHandler);
}
protected override void UnregisterCallbacksFromTarget()
{
target.UnregisterCallback<PointerDownEvent>(PointerDownHandler);
target.UnregisterCallback<PointerMoveEvent>(PointerMoveHandler);
target.UnregisterCallback<PointerUpEvent>(PointerUpHandler);
target.UnregisterCallback<PointerCaptureOutEvent>(PointerCaptureOutHandler);
}
private Vector2 targetStartPosition { get; set; }
private Vector3 pointerStartPosition { get; set; }
private bool enabled { get; set; }
private VisualElement root { get; }
private void PointerDownHandler(PointerDownEvent evt)
{
targetStartPosition = target.transform.position;
pointerStartPosition = evt.position;
target.CapturePointer(evt.pointerId);
enabled = true;
}
private void PointerMoveHandler(PointerMoveEvent evt)
{
if (enabled && target.HasPointerCapture(evt.pointerId))
{
Vector3 pointerDelta = evt.position - pointerStartPosition;
target.transform.position = new Vector2(
Mathf.Clamp(targetStartPosition.x + pointerDelta.x, 0, target.panel.visualTree.worldBound.width),
Mathf.Clamp(targetStartPosition.y + pointerDelta.y, 0, target.panel.visualTree.worldBound.height));
}
}
private void PointerUpHandler(PointerUpEvent evt)
{
if (enabled && target.HasPointerCapture(evt.pointerId))
{
target.ReleasePointer(evt.pointerId);
}
}
private void PointerCaptureOutHandler(PointerCaptureOutEvent evt)
{
if (enabled)
{
VisualElement slotsContainer = root.Q<VisualElement>("slots");
UQueryBuilder<VisualElement> allSlots =
slotsContainer.Query<VisualElement>(className: "slot");
UQueryBuilder<VisualElement> overlappingSlots =
allSlots.Where(OverlapsTarget);
VisualElement closestOverlappingSlot =
FindClosestSlot(overlappingSlots);
Vector3 closestPos = Vector3.zero;
if (closestOverlappingSlot != null)
{
closestPos = RootSpaceOfSlot(closestOverlappingSlot);
closestPos = new Vector2(closestPos.x - 5, closestPos.y - 5);
}
target.transform.position =
closestOverlappingSlot != null ?
closestPos :
targetStartPosition;
enabled = false;
}
}
private bool OverlapsTarget(VisualElement slot)
{
return target.worldBound.Overlaps(slot.worldBound);
}
private VisualElement FindClosestSlot(UQueryBuilder<VisualElement> slots)
{
List<VisualElement> slotsList = slots.ToList();
float bestDistanceSq = float.MaxValue;
VisualElement closest = null;
foreach (VisualElement slot in slotsList)
{
Vector3 displacement =
RootSpaceOfSlot(slot) - target.transform.position;
float distanceSq = displacement.sqrMagnitude;
if (distanceSq < bestDistanceSq)
{
bestDistanceSq = distanceSq;
closest = slot;
}
}
return closest;
}
private Vector3 RootSpaceOfSlot(VisualElement slot)
{
Vector2 slotWorldSpace = slot.parent.LocalToWorld(slot.layout.position);
return root.WorldToLocal(slotWorldSpace);
}
}
Untuk mengaktifkan drag-and-drop di jendela kustom, sesaat ketika jendela terbuka.
Pada DragAndDropWindow.cs
, tambahkan metode CreateGUI()
untuk meluruskan kelas DragAndDropManipulator
:
DragAndDropManipulator manipulator =
new(rootVisualElement.Q<VisualElement>("object"));
Pergi ke bar menu Unity, klik Window > UI Toolkit > Drag And Drop. Di jendela kustom yang dibuka, Anda dapat menyeret objek ke slot apa pun.
Contoh UI Drag-and-drop ditambahkan dalam Unity Panties20212