Нашел решение, которое, похоже, и используется Google для запуска Android TV.
Вкратце: создайте пользовательский VerticalGridView
и переопределите его метод focusSearch()
, чтобы определить, как перемещать / менять элементы.
Что-то похожее на это:
class EditableVerticalGridView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0) :
VerticalGridView(context, attrs, defStyle) {
override fun focusSearch(focused: View, direction: Int): View {
return if (focused.isSelected) {
swapItemsIfNeeded(focused, direction)
} else super.focusSearch(focused, direction)
}
private fun swapItemsIfNeeded(focused: View, direction: Int): View {
val position = getChildAdapterPosition(focused)
if (!itemAnimator.isRunning) {
if (canMoveInDirection(position, direction)) {
when (direction) {
FOCUS_LEFT -> moveChannel(position, position - 1)
FOCUS_UP -> moveChannel(position, position - NUM_COLUMN)
FOCUS_RIGHT -> moveChannel(position, position + 1)
FOCUS_DOWN -> moveChannel(position, position + NUM_COLUMN)
}
}
}
return focused
}
private fun canMoveInDirection(position: Int, direction: Int): Boolean {
when (direction) {
FOCUS_LEFT -> {
return position % NUM_COLUMN > 0
}
FOCUS_UP -> {
return position - NUM_COLUMN >= 0
}
FOCUS_RIGHT -> {
return !(position % NUM_COLUMN >= (NUM_COLUMN - 1) ||
position >= adapter.itemCount - 1)
}
FOCUS_DOWN -> {
return position + NUM_COLUMN <= adapter.itemCount - 1
}
else -> {
return false
}
}
}
private fun moveChannel(fromPosition: Int, toPosition: Int) {
(adapter as AllowedChannelAdapter).moveChannel(fromPosition, toPosition)
}
companion object {
private const val NUM_COLUMN: Int = 6
}
}
... и функция moveChannel()
:
fun moveChannel(from: Int, to: Int) {
var offset = 1
if (from >= 0 && from <= channelItems.size - 1 && to >= 0 && to <= channelItems.size - 1) {
val fromItem = channelItems[from]
channelItems[from] = channelItems[to]
channelItems[to] = fromItem
notifyItemMoved(from, to)
val positionDifference = to - from
if (Math.abs(positionDifference) > 1) {
if (positionDifference > 0) {
offset = -1
}
notifyItemMoved(to + offset, from)
}
}
}
const int i0 = 5;
//int i1 = const_cast<int>(i0); // compilation error
int i2 = (int)i0; // okay
int i3 = 5;
//const int i4 = const_cast<const int>(i3); // compilation error
const int i5 = (const int)i3; // okay
Ошибки компиляции вызываются, потому что Вы не бросаете константу далеко/добавлять константа. Вместо этого Вы копируете i0. Для той операции никакой бросок не требуется вообще:
int i1 = i0;
const int i4 = i3;
Тип, к которому Вы бросаете, должен на самом деле быть указателем или ссылкой. Иначе использование const_cast не имеет смысла, так как Вы могли прямо скопировать его. Для указателей, например, можно выбросить константу, потому что разыменование указателя приведет к другому типу для a const T*
(урожаи const T
) чем для a T*
(урожаи T
). Для ссылок то же верно: T&
получит доступ к объекту с помощью другого этого типа указателя, чем использование const T&
. Теперь, что Вы действительно хотели заархивировать:
const int i0 = 5;
//int & i1 = const_cast<int&>(i0); // okay (but dangerous)
int & i2 = (int&)i0; // okay (but dangerous)
int i3 = 5;
//const int&i4 = const_cast<const int&>(i3); // ok now and valid!
const int&i5 = (const int&)i3; // okay too!
Вышеупомянутое может привести к неопределенному поведению, когда Вы пишете в первоначально объект константы через ссылку на неконстанту (на самом деле, просто бросание и читать его не являются неопределенным поведением сам по себе. Но если Вы выбрасываете константу, можно также записать в нее, который затем приводит к неопределенному поведению),
Это - ошибка, потому что в стандарте говорится, что это не позволяется. Стандарт перечисляет виды преобразований это const_cast
позволяется сделать, и это запрещает что-либо не в списке. Это позволяет следующее:
Так как Ваши типы не являются ни одним из тех, им не позволяют.
С другой стороны для примеров, которые Вы дали, не нужно const_cast
, также.
Для первой ошибки. const_cast может только использоваться на типах указателей или ссылочных типах. "интервал" не ни один. Это может или не может быть стандартом C++ (не мог найти хорошую ссылку). Но это имеет место для определенных реализаций, таких как компилятор C++ MS.
Для второй ошибки. const_cast может только использоваться для удаления константы, или энергозависимый спецификатор не добавляют его.
Ссылка: http://msdn.microsoft.com/en-us/library/bz6at95h (по сравнению с 80) .aspx