* [NUI] Fix scrollableBase focus issue.
fix several issue on focus of scrollableBase.
1. fix wrong focus fallback when next focused children is invisble.
- if current focused object is children of scrollableBase,
keep focus to current focused object.
- if current focused object is out of scrollableBase,
to keep focus within the scrollableBase, set focus on scrollableBase.
2. fix wrong next focus returns on next find failed case.
if next focus find is failed, we can move scroll when key can move
foward and backward only not other directions.
In other direction inputs, escape the scrollableBase.
3. fix wrong escape condition of EOS(end of scroll).
we escape scrollableBase in EOS, but we need to reached EOS firstly,
and escape scrollableBase on next key input to move out.
4. add conditional debugging log.
5. fix focus samples.
add text label for notify prev/current focused object.
fix title of items.
make padding longer on items.
* [NUI] fix samples.
* [NUI] return null as nextFocusedView will always null.
* [NUI] Update scrollableBase focus logic for missing cases.
* [NUI] Update scrollableBase focus to find next focus properly.
* [NUI] remove unreachable code.
public partial class ScrollableBase : Control
{
static bool LayoutDebugScrollableBase = false; // Debug flag
+ static bool focusDebugScrollableBase = false; // Debug flag
private Direction mScrollingDirection = Direction.Vertical;
private bool mScrollEnabled = true;
private int mScrollDuration = 125;
}
}
-
/// <inheritdoc/>
[EditorBrowsable(EditorBrowsableState.Never)]
public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
float targetPosition = -(ScrollingDirection == Direction.Horizontal ? ContentContainer.CurrentPosition.X : ContentContainer.CurrentPosition.Y);
float stepDistance = (stepScrollDistance != 0? stepScrollDistance : (isHorizontal ? Size.Width * 0.25f : Size.Height * 0.25f));
+ bool forward = ((isHorizontal && direction == View.FocusDirection.Right) ||
+ (!isHorizontal && direction == View.FocusDirection.Down));
+ bool backward = ((isHorizontal && direction == View.FocusDirection.Left) ||
+ (!isHorizontal && direction == View.FocusDirection.Up));
+
+ // Reached end of scroll. move out focus from ScrollableBase.
+ if ((forward && maxScrollDistance - targetPosition < 0.1f) || (backward && targetPosition < 0.1f))
+ {
+ var next = FocusManager.Instance.GetNearestFocusableActor(this.Parent, this, direction);
+ Debug.WriteLineIf(focusDebugScrollableBase, $"Reached End of Scroll. Next focus target {next}:{next?.ID}");
+ return next;
+ }
+
View nextFocusedView = FocusManager.Instance.GetNearestFocusableActor(this, currentFocusedView, direction);
+ if (focusDebugScrollableBase)
+ {
+ global::System.Text.StringBuilder debugMessage = new global::System.Text.StringBuilder("=========================================================\n");
+ debugMessage.Append($"GetNextFocusableView On: {this}:{this.ID}\n");
+ debugMessage.Append($"----------------Current: {currentFocusedView}:{currentFocusedView?.ID}\n");
+ debugMessage.Append($"-------------------Next: {nextFocusedView}:{nextFocusedView?.ID}\n");
+ debugMessage.Append($"--------------Direction: {direction}\n");
+ debugMessage.Append("=========================================================");
+ Debug.WriteLineIf(focusDebugScrollableBase, debugMessage);
+ }
+
if (nextFocusedView != null)
{
if (null != FindDescendantByID(nextFocusedView.ID))
if (IsChildNearlyVisble(nextFocusedView, stepDistance) == true)
{
ScrollToChild(nextFocusedView, true);
- }
- else
- {
- if ((isHorizontal && direction == View.FocusDirection.Right) ||
- (!isHorizontal && direction == View.FocusDirection.Down))
- {
- targetPosition += stepDistance;
- targetPosition = targetPosition > maxScrollDistance ? maxScrollDistance : targetPosition;
-
- }
- else if ((isHorizontal && direction == View.FocusDirection.Left) ||
- (!isHorizontal && direction == View.FocusDirection.Up))
- {
- targetPosition -= stepDistance;
- targetPosition = targetPosition < 0 ? 0 : targetPosition;
- }
-
- ScrollTo(targetPosition, true);
+ return nextFocusedView;
}
}
}
- else
+
+ if (forward || backward)
{
- if((isHorizontal && direction == View.FocusDirection.Right) ||
- (!isHorizontal && direction == View.FocusDirection.Down))
+ // Fallback to current focus or scrollableBase till next focus visible in scrollable.
+ if (null != currentFocusedView && null != FindDescendantByID(currentFocusedView.ID))
+ {
+ nextFocusedView = currentFocusedView;
+ }
+ else
+ {
+ return this;
+ }
+
+ if (forward)
{
targetPosition += stepDistance;
targetPosition = targetPosition > maxScrollDistance ? maxScrollDistance : targetPosition;
}
- else if((isHorizontal && direction == View.FocusDirection.Left) ||
- (!isHorizontal && direction == View.FocusDirection.Up))
+ else if (backward)
{
targetPosition -= stepDistance;
targetPosition = targetPosition < 0 ? 0 : targetPosition;
ScrollTo(targetPosition, true);
- // End of scroll. escape.
- if ((targetPosition == 0 || targetPosition == maxScrollDistance) == false)
- {
- return this;
- }
-
+ Debug.WriteLineIf(focusDebugScrollableBase, $"ScrollTo :({targetPosition})");
}
+
+ Debug.WriteLineIf(focusDebugScrollableBase, $"return end : {nextFocusedView}:{nextFocusedView?.ID}");
return nextFocusedView;
}
int SCROLLMAX = 50;
public View root;
+ private string GetChildText(View parent)
+ {
+ if (parent != null)
+ {
+ foreach(View child in parent.Children)
+ {
+ if (child is TextLabel label)
+ {
+ return $"{label.Text}";
+ }
+ }
+ }
+
+ return "";
+ }
+
+ private string GetLabelText(int i)
+ {
+ switch (i)
+ {
+ case 0:
+ return "[1st]";
+ case 1:
+ return "[2nd]";
+ case 2:
+ return "[3rd]";
+ default:
+ return $"[{i+1}th]";
+ }
+ }
+
public void Activate()
{
};
window.Add(root);
+ var focusInfo = new TextLabel()
+ {
+ BackgroundColor = Color.Yellow,
+ TextColor = Color.Red,
+ Text = "Prev:[N/A] Current:[N/A]"
+ };
+ root.Add(focusInfo);
+
FocusManager.Instance.EnableDefaultAlgorithm(true);
+ FocusManager.Instance.FocusChanged += (object s, FocusManager.FocusChangedEventArgs e) =>
+ {
+ string prev = "[N/A]";
+ string cur = "[N/A]";
+ if (e.Previous != null)
+ {
+ var prevView = e.Previous;
+ prev = $"{prevView.Name}[{prevView.ID}]{GetChildText(prevView)}";
+ }
+
+ if (e.Current != null)
+ {
+ var curView = e.Current;
+ cur = $"{curView.Name}[{curView.ID}]{GetChildText(curView)}";
+ }
+
+ focusInfo.Text = $"Prev:{prev} Current:{cur}";
+ Console.WriteLine($"Focus Changed Prev:{prev} => Current:{cur}");
+ };
var top = new Button()
{
{
LinearOrientation = LinearLayout.Orientation.Vertical,
HorizontalAlignment = HorizontalAlignment.Center,
- CellPadding = new Size2D(10, 10),
+ CellPadding = new Size2D(10, 30),
}
};
root.Add(verticalScrollView);
};
var label = new TextLabel()
{
- Text = $"[{i}]",
+ Text = GetLabelText(i),
PointSize = 20,
};
colorItem.Add(label);
{
LinearOrientation = LinearLayout.Orientation.Horizontal,
VerticalAlignment = VerticalAlignment.Center,
- CellPadding = new Size2D(10, 10),
+ CellPadding = new Size2D(30, 10),
}
};
horizontalLayout.Add(horizontalScrollView);
};
var label = new TextLabel()
{
- Text = $"[{i}]",
+ Text = GetLabelText(i),
PointSize = 20,
};
colorItem.Add(label);
int SCROLLMAX = 50;
public View root;
+ private string GetChildText(View parent)
+ {
+ if (parent != null)
+ {
+ foreach(View child in parent.Children)
+ {
+ if (child is TextLabel label)
+ {
+ return $"{label.Text}";
+ }
+ }
+ }
+
+ return "";
+ }
+
+ private string GetLabelText(int i)
+ {
+ switch (i)
+ {
+ case 0:
+ return "[1st]";
+ case 1:
+ return "[2nd]";
+ case 2:
+ return "[3rd]";
+ default:
+ return $"[{i+1}th]";
+ }
+ }
+
public void Activate()
{
};
window.Add(root);
+ var focusInfo = new TextLabel()
+ {
+ BackgroundColor = Color.Yellow,
+ TextColor = Color.Red,
+ //Focusable = true,
+ Text = "Prev:[N/A] Current:[N/A]"
+ };
+ root.Add(focusInfo);
+
FocusManager.Instance.EnableDefaultAlgorithm(true);
+ FocusManager.Instance.FocusChanged += (object s, FocusManager.FocusChangedEventArgs e) =>
+ {
+ string prev = "[N/A]";
+ string cur = "[N/A]";
+ if (e.Previous != null)
+ {
+ var prevView = e.Previous;
+ prev = $"{prevView.Name}[{prevView.ID}]{GetChildText(prevView)}";
+ }
+
+ if (e.Current != null)
+ {
+ var curView = e.Current;
+ cur = $"{curView.Name}[{curView.ID}]{GetChildText(curView)}";
+ }
+
+ focusInfo.Text = $"Prev:{prev} Current:{cur}";
+ Console.WriteLine($"Focus Changed Prev:{prev} => Current:{cur}");
+ };
var top = new Button()
{
{
LinearOrientation = LinearLayout.Orientation.Vertical,
HorizontalAlignment = HorizontalAlignment.Center,
- CellPadding = new Size2D(10, 10),
+ CellPadding = new Size2D(10, 30),
}
};
root.Add(verticalScrollView);
VerticalAlignment = VerticalAlignment.Center,
CellPadding = new Size2D(10, 10),
}
+
};
var label = new TextLabel()
{
- Text = $"[{i}]",
+ Text = GetLabelText(i),
PointSize = 20,
};
+
colorItem.Add(label);
verticalScrollView.Add(colorItem);
}
{
LinearOrientation = LinearLayout.Orientation.Horizontal,
VerticalAlignment = VerticalAlignment.Center,
- CellPadding = new Size2D(10, 10),
+ CellPadding = new Size2D(30, 10),
}
};
horizontalLayout.Add(horizontalScrollView);
};
var label = new TextLabel()
{
- Text = $"[{i}]",
+ Text = GetLabelText(i),
PointSize = 20,
};
colorItem.Add(label);
int SCROLLMAX = 50;
public View root;
+ private string GetChildText(View parent)
+ {
+ if (parent != null)
+ {
+ foreach(View child in parent.Children)
+ {
+ if (child is TextLabel label)
+ {
+ return $"{label.Text}";
+ }
+ }
+ }
+
+ return "";
+ }
+
+ private string GetLabelText(int i)
+ {
+ switch (i)
+ {
+ case 0:
+ return "[1st]";
+ case 1:
+ return "[2nd]";
+ case 2:
+ return "[3rd]";
+ default:
+ return $"[{i+1}th]";
+ }
+ }
+
public void Activate()
{
};
window.Add(root);
+ var focusInfo = new TextLabel()
+ {
+ BackgroundColor = Color.Yellow,
+ TextColor = Color.Red,
+ Text = "Prev:[N/A] Current:[N/A]"
+ };
+ root.Add(focusInfo);
+
FocusManager.Instance.EnableDefaultAlgorithm(true);
+ FocusManager.Instance.FocusChanged += (object s, FocusManager.FocusChangedEventArgs e) =>
+ {
+ string prev = "[N/A]";
+ string cur = "[N/A]";
+ if (e.Previous != null)
+ {
+ var prevView = e.Previous;
+ prev = $"{prevView.Name}[{prevView.ID}]{GetChildText(prevView)}";
+ }
+
+ if (e.Current != null)
+ {
+ var curView = e.Current;
+ cur = $"{curView.Name}[{curView.ID}]{GetChildText(curView)}";
+ }
+
+ focusInfo.Text = $"Prev:{prev} Current:{cur}";
+ Console.WriteLine($"Focus Changed Prev:{prev} => Current:{cur}");
+ };
var top = new Button()
{
{
LinearOrientation = LinearLayout.Orientation.Vertical,
HorizontalAlignment = HorizontalAlignment.Center,
- CellPadding = new Size2D(10, 10),
+ CellPadding = new Size2D(10, 30),
}
};
root.Add(verticalScrollView);
};
var label = new TextLabel()
{
- Text = $"[{i}]",
+ Text = GetLabelText(i),
PointSize = 20,
};
{
LinearOrientation = LinearLayout.Orientation.Horizontal,
VerticalAlignment = VerticalAlignment.Center,
- CellPadding = new Size2D(10, 10),
+ CellPadding = new Size2D(30, 10),
}
};
horizontalLayout.Add(horizontalScrollView);
};
var label = new TextLabel()
{
- Text = $"[{i}]",
+ Text = GetLabelText(i),
PointSize = 20,
};