Refactor scroll state management and enhance BaseScroll configurability#6
Refactor scroll state management and enhance BaseScroll configurability#6kurobon-jp wants to merge 2 commits into
Conversation
* **Enhance Scroller lifecycle:**
* Ensure `_scroller` is always initialized in `BaseScroll` by providing a default instance if `null`, removing numerous null checks.
* Make `ScrollStatus` enum public and introduce `OnScrollStateChanged` event in `Scroller` for external observation of scroll state.
* Update all internal status changes in `Scroller` to use the new `Status` property, which dispatches the `OnScrollStateChanged` event.
* **Improve BaseScroll configurability and events:**
* Expose `OnScrollStateChanged` event from `Scroller` via `BaseScroll`.
* Add `IsIdling` property to `BaseScroll`.
* Convert `IsDraggable` and `IsScrollable` into serialized fields in `BaseScroll`, enabling direct configuration in the Inspector.
* Update drag and scroll handlers in `BaseScroll` to respect the new `IsDraggable` and `IsScrollable` fields.
* Remove redundant null checks on `_scroller` throughout `BaseScroll`.
* **Cleanup:**
* Remove `#if UNITY_EDITOR` block for `_tracker.Clear()` in `BaseScroll.OnDisable`.
* Created a new `BaseScrollEditor` class to consolidate common UI Toolkit inspector properties for various scroll components. * Centralized the display of properties such as `_scroller._axis`, `_viewport`, `_content`, `_contentPadding`, `_space`, `_isScrollable`, `_isDraggable`, `_scroller`, and `_scroller._onValueChanged` in the base editor. * Implemented a value change callback for `_isDraggable` to dynamically enable or disable the `_scroller` property field. * Introduced a `protected virtual void CreateInherentProperties(VisualElement container)` method for derived editors to add their specific properties. * Refactored `CarouselScrollEditor`, `FixedGridScrollEditor`, `FixedListScrollEditor`, `LazyLayoutListScrollEditor`, and `SizedListScrollEditor` to inherit from `BaseScrollEditor`. * Moved the unique property fields in these derived editors into their respective `CreateInherentProperties` overrides, eliminating redundant code.
🐙 Octopus Review — PR #6SummaryこのPRは、スクロール状態管理のリファクタリングとエディタUIの共通化を行います。 Score
Risk Assessment
Positive Highlights
Important Files Changed
Diagramgraph TD
BaseScrollEditor["BaseScrollEditor (NEW)"]
CarouselEd["CarouselScrollEditor"]
FixedGridEd["FixedGridScrollEditor"]
FixedListEd["FixedListScrollEditor"]
LazyLayoutEd["LazyLayoutListScrollEditor"]
SizedListEd["SizedListScrollEditor"]
BaseScrollEditor --> CarouselEd
BaseScrollEditor --> FixedGridEd
BaseScrollEditor --> FixedListEd
BaseScrollEditor --> LazyLayoutEd
BaseScrollEditor --> SizedListEd
BaseScroll["BaseScroll (MODIFIED)"]
Scroller["Scroller (MODIFIED)"]
ScrollStatus["ScrollStatus enum (PUBLIC)"]
BaseScroll -- "lazy init via ??" --> Scroller
BaseScroll -- "exposes event" --> ScrollStatusEvt["OnScrollStateChanged"]
Scroller -- "Status property fires" --> ScrollStatusEvt
Scroller -- "uses" --> ScrollStatus
classDef added fill:#4ade80,stroke:#166534,color:#000
classDef changed fill:#fbbf24,stroke:#92400e,color:#000
classDef unchanged fill:#374151,stroke:#6b7280,color:#e5e7eb
class BaseScrollEditor added
class BaseScroll,Scroller changed
class ScrollStatus added
class CarouselEd,FixedGridEd,FixedListEd,LazyLayoutEd,SizedListEd changed
class ScrollStatusEvt unchanged
Last reviewed commit: (latest in diff) Checklist
|
There was a problem hiding this comment.
9 files reviewed, 6 findings | View scores & details
🟡🔵💡 Additional findings
| Severity | File | Title | Description |
|---|---|---|---|
| 🟡 | Assets/Runtime/BaseScroll.cs:L85 |
OnDisableからの_tracker.Clear()削除によりエディタでDrivenRectTransformTrackerリークの可能性 | 以前はOnDisable内に#if UNITY_EDITORブロックで_tracker.Clear()が呼ばれていたが、このPRで削除された。_tracker(DrivenRectTransformTracker)はUnityエディタ上でRectTransformのプロパティをロックするために使われており、コンポーネント無効化時にクリアしないと、エディタ上でビューポートやコンテンツのPivot/SizeDeltaが編集不能のままになる可能性がある。OnValidateにはまだ_tracker.Clear()が残っているが、OnDisable時にもクリアすべきである。 |
| 🟡 | Assets/Editor/CarouselScrollEditor.cs:L9 |
CarouselScrollEditorで_contentPaddingと_spaceが追加されたが、CarouselScrollに該当フィールドが存在するか不明 | BaseScrollEditor.CreateInspectorGUIは_contentPaddingと_spaceを全サブクラスのインスペクタに追加しているが、旧CarouselScrollEditorではこれらのフィールドは描画されていなかった(_spaceのみ描画)。CarouselScrollクラスに_contentPaddingフィールドが存在しない場合、serializedObject.FindProperty("_contentPadding")はnullを返し、PropertyFieldに渡されても描画されないだけなので実害は少ないが、意図しないフィールドが表示される可能性がある。コードベースのコンテキストからCarouselScrollの定義が確認できないため、要確認を推奨する。 |
| 🟡 | Assets/Runtime/BaseScroll.cs:L51 |
OnValueChangedプロパティのみ_scrollerフィールドを直接参照しており、遅延初期化パターンと非一貫 | public ScrollEvent OnValueChanged => _scroller.OnValueChanged;は_scrollerフィールドを直接参照しているが、他の全プロパティはScroller(遅延初期化プロパティ)経由でアクセスしている。_scrollerがnullの場合(シリアライズされていない場合など)にNullReferenceExceptionが発生する可能性がある。一貫性のためにもScroller.OnValueChangedに変更すべきである。 |
| 🔵 | Assets/Runtime/Utils/Scroller.cs:L7 |
ScrollStatusのpublic化はBreaking Changeであり、名前空間の公開APIとなる | ScrollStatusがprivate enumからpublic enumに昇格したことで、SimpleScroll名前空間の公開APIの一部となった。将来的にステータスの追加・削除・リネームが破壊的変更になる。現在Coastingは物理的な挙動(慣性コースティング)を表しているが、外部から参照されることを考慮した命名・ドキュメントの整備を検討すべきである。また、パッケージのsemantic versioningの更新が必要。 |
| 💡 | Assets/Editor/BaseScrollEditor.cs:L31 |
BaseScrollEditor.csの末尾に改行がない | ファイル末尾に改行(newline)がない。Gitの差分やエディタツールによっては警告が表示される場合がある。コードベース内の他のファイルと合わせて末尾改行を追加することを推奨。 |
Reviewed by Octopus Review, an AI-powered PR review tool.
| void IEndDragHandler.OnEndDrag(PointerEventData e) | ||
| { | ||
| if (DataSource == null || _pointerId != e.pointerId) return; | ||
| _pointerId = int.MinValue; |
There was a problem hiding this comment.
🟠 IsDraggable=false時のOnEndDragでポインターIDがリセットされず次のドラッグが受け付けられない可能性
IsDraggableがfalseの場合、OnEndDrag内でScroller.Stop()を呼んでreturnしているが、その直前に_pointerId = int.MinValueのリセットが行われている(diff上ではL190)。一方、OnBeginDragでは!IsDraggableチェックが追加されたため、IsDraggableがfalse→trueに動的変更された場合でも問題は起きにくい。ただし、IsDraggable=falseでOnEndDragが呼ばれた際にScroller.Stop()を呼ぶことでOnScrollStateChangedイベントが発火し、呼び出し元が意図しない状態変化通知を受け取る可能性がある。Stop()呼び出しが本当に必要か、またIsIdlingチェックを挟むべきか検討を推奨する。
| _pointerId = int.MinValue; | |
| void IEndDragHandler.OnEndDrag(PointerEventData e) | |
| { | |
| if (DataSource == null || _pointerId != e.pointerId) return; | |
| _pointerId = int.MinValue; | |
| if (!IsDraggable) | |
| { | |
| if (!Scroller.IsIdling) Scroller.Stop(); | |
| return; | |
| } | |
| var targetPosition = Scroller.OnEndDrag(e); | |
| OnDrag(targetPosition); | |
| } |
📌 Grounding
Minimum fix scope: IEndDragHandler.OnEndDrag内のStop()呼び出しにIsIdlingガードを追加する1行の変更。
Suggested regression test:
// IsDraggable=falseでEndDragを呼んだ際にOnScrollStateChangedが不必要に発火しないことを確認
// scroll.IsDraggable = false;
// BeginDrag (IsDraggable=trueの状態で) → IsDraggable=falseに変更 → EndDrag
// OnScrollStateChangedの発火回数が期待値と一致することをアサート
🤖 AI Fix Prompt
Fix the following High (Bug) issue in `Assets/Runtime/BaseScroll.cs` at lines 193-200:
Problem: `IsDraggable`が`false`の場合、`OnEndDrag`内で`Scroller.Stop()`を呼んで`return`しているが、その直前に`_pointerId = int.MinValue`のリセットが行われている(diff上ではL190)。一方、`OnBeginDrag`では`!IsDraggable`チェックが追加されたため、`IsDraggable`が`false`→`true`に動的変更された場合でも問題は起きにくい。ただし、`IsDraggable=false`で`OnEndDrag`が呼ばれた際に`Scroller.Stop()`を呼ぶことで`OnScrollStateChanged`イベントが発火し、呼び出し元が意図しない状態変化通知を受け取る可能性がある。`Stop()`呼び出しが本当に必要か、また`IsIdling`チェックを挟むべきか検討を推奨する。
Suggested fix:
void IEndDragHandler.OnEndDrag(PointerEventData e)
{
if (DataSource == null || _pointerId != e.pointerId) return;
_pointerId = int.MinValue;
if (!IsDraggable)
{
if (!Scroller.IsIdling) Scroller.Stop();
return;
}
var targetPosition = Scroller.OnEndDrag(e);
OnDrag(targetPosition);
}
Scope: `IEndDragHandler.OnEndDrag`内のStop()呼び出しにIsIdlingガードを追加する1行の変更。
No description provided.