相機有一個視口,你可以想象它是一個可移動的疊加層以上的內容(一些背景顯示在沒有內容放置的區域)。爲了簡單起見,我將從內容轉換(例如縮放)中分離滾動(即移動視口)。
![enter image description here](https://i.stack.imgur.com/5yuKV.png)
基於該心理模型,可以定義可滾動邊界成爲你內容的邊界以及當前視口的(在大於視口較小的內容的情況下例如)一個可能是空的部分。每次滾動操作(增加/減少當前視口內的空白空間)或內容操作(轉換和邊界更改)後,需要重新計算可滾動邊界。如果將滾動限制爲可滾動邊界,則可以確保視口內的空白空間不會因滾動操作而增加。
您可以創建一個ObjectBinding scrollableBounds,它綁定到內容的bounds-in-local和local-to-parent-transform屬性以及視口邊界。然後,您可以創建綁定到綁定的scollableBoundsProperty。滾動時可以訪問該屬性,以便在應用它之前限制翻譯,從而防止視口內的空白空間增加。
ObjectBinding<Bounds> scrollableBoundsBinding = new ObjectBinding<>() {
{
// TODO: bind to dependencies: viewport bounds and content bounds
// TODO: (transformed to the same coordinate system)
bind(camera.boundsInParentProperty(),
contentPane.boundsInLocalProperty(),
contentPane.localToParentTransformProperty());
}
@Override protected Bounds computeValue() {
// TODO: compute union of viewport and content bounds
return unionBounds(viewportBounds, contentBounds);
}
};
ObjectProperty<Bounds> scrollableBoundsProperty = new SimpleObjectProperty<>(
scrollableBoundsBinding);
// ...
// on mouse drag:
// dx, dy: relative mouse movement
// tx, ty: current scrolling
// mintx, maxtx, minty, maxty: translation range
// (taken from scrollable bounds and viewport size)
if (dx < 0) { tx = max(mintx, tx + dx); }
else { tx = min(maxtx, tx + dx); }
if (dy < 0) { ty = max(minty, ty + dy); }
else { ty = min(maxty, ty + dy); }
當內容完全適合視口時,您可能想進一步限制滾動,例如,將內容放置在左上角。在這種情況下,您還可以限制最小縮放級別,以使內容儘可能大。
關於可用性的說明:正如已經指出的另一個答案,您可能想考慮允許將內容拖動一下,可能會降低效率,嘗試從內容滾動到更遠處,可能與行爲在Safari中通過觸摸板滾動。然後,當交互完成時,您可以轉換回來而不是捕捉,以便再次將視口限制爲內容。
您允許在內容上進行什麼樣的轉換? –
@JoseMartinez我允許大多數形式的轉換,但我只想尋找約束條件來適用於沿照相機沿X軸和Y軸移動,而沒有應用除Z軸轉換之外的其他轉換 –