- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
1145 lines
41 KiB
Python
1145 lines
41 KiB
Python
"""
|
|
Android Widget Adapter 组件 — ListAdapter, SpinnerAdapter, ArrayAdapter (扩展),
|
|
CursorAdapter (扩展), RecyclerView.Adapter (扩展), RecyclerView.ViewHolder,
|
|
PagerAdapter, FragmentPagerAdapter, PagerTitleStrip 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Callable, Dict, Generic, List, Optional, Tuple, TypeVar
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
|
|
T = TypeVar("T")
|
|
|
|
__all__ = [
|
|
"ListAdapter", "SpinnerAdapter", "WrapperListAdapter",
|
|
"HeaderViewListAdapter", "ArrayAdapter", "CursorAdapter",
|
|
"SimpleCursorAdapter", "ResourceCursorAdapter", "SimpleAdapter",
|
|
"BaseAdapter", "RecyclerView",
|
|
"PagerAdapter", "FragmentPagerAdapter", "FragmentStatePagerAdapter",
|
|
"PagerTitleStrip", "PagerTabStrip",
|
|
]
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# 适配器常量
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
ADAPTER_IGNORE_ITEM_VIEW_TYPE = -1
|
|
ADAPTER_NO_SELECTION = -1
|
|
ADAPTER_INVALID_POSITION = -1
|
|
ADAPTER_INVALID_ROW_ID = -1
|
|
ADAPTER_HAS_STABLE_IDS = True
|
|
ADAPTER_NO_STABLE_IDS = False
|
|
|
|
PAGER_POSITION_UNCHANGED = -1
|
|
PAGER_POSITION_NONE = -2
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# BaseAdapter (扩展)
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class BaseAdapter(Stub):
|
|
"""BaseAdapter — 基础适配器 (完整版)"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._observers: List[Any] = []
|
|
|
|
def getCount(self) -> int:
|
|
return 0
|
|
|
|
def getItem(self, position: int) -> Optional[Any]:
|
|
return None
|
|
|
|
def getItemId(self, position: int) -> int:
|
|
return position
|
|
|
|
def getView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return None
|
|
|
|
def getItemViewType(self, position: int) -> int:
|
|
return ADAPTER_IGNORE_ITEM_VIEW_TYPE
|
|
|
|
def getViewTypeCount(self) -> int:
|
|
return 1
|
|
|
|
def hasStableIds(self) -> bool:
|
|
return False
|
|
|
|
def isEmpty(self) -> bool:
|
|
return self.getCount() == 0
|
|
|
|
def registerDataSetObserver(self, observer: Any):
|
|
self._observers.append(observer)
|
|
|
|
def unregisterDataSetObserver(self, observer: Any):
|
|
self._observers = [o for o in self._observers if o is not observer]
|
|
|
|
def notifyDataSetChanged(self):
|
|
for o in self._observers:
|
|
if hasattr(o, 'onChanged'):
|
|
o.onChanged()
|
|
|
|
def notifyDataSetInvalidated(self):
|
|
for o in self._observers:
|
|
if hasattr(o, 'onInvalidated'):
|
|
o.onInvalidated()
|
|
|
|
def areAllItemsEnabled(self) -> bool:
|
|
return True
|
|
|
|
def isEnabled(self, position: int) -> bool:
|
|
return True
|
|
|
|
def getDropDownView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return self.getView(position, convertView, parent)
|
|
|
|
def toString(self) -> str:
|
|
return f"BaseAdapter(count={self.getCount()})"
|
|
|
|
def equals(self, other: Any) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return id(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ListAdapter
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ListAdapter(Stub):
|
|
"""ListAdapter — 列表适配器接口"""
|
|
|
|
def getCount(self) -> int:
|
|
return 0
|
|
|
|
def getItem(self, position: int) -> Optional[Any]:
|
|
return None
|
|
|
|
def getItemId(self, position: int) -> int:
|
|
return position
|
|
|
|
def getView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return None
|
|
|
|
def isEmpty(self) -> bool:
|
|
return self.getCount() == 0
|
|
|
|
def registerDataSetObserver(self, observer: Any):
|
|
pass
|
|
|
|
def unregisterDataSetObserver(self, observer: Any):
|
|
pass
|
|
|
|
def areAllItemsEnabled(self) -> bool:
|
|
return True
|
|
|
|
def isEnabled(self, position: int) -> bool:
|
|
return True
|
|
|
|
def getItemViewType(self, position: int) -> int:
|
|
return ADAPTER_IGNORE_ITEM_VIEW_TYPE
|
|
|
|
def getViewTypeCount(self) -> int:
|
|
return 1
|
|
|
|
def hasStableIds(self) -> bool:
|
|
return False
|
|
|
|
def toString(self) -> str:
|
|
return f"ListAdapter@{hex(id(self))}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# SpinnerAdapter
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class SpinnerAdapter(Stub):
|
|
"""SpinnerAdapter — 下拉适配器接口"""
|
|
|
|
def getCount(self) -> int:
|
|
return 0
|
|
|
|
def getItem(self, position: int) -> Optional[Any]:
|
|
return None
|
|
|
|
def getItemId(self, position: int) -> int:
|
|
return position
|
|
|
|
def getView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return None
|
|
|
|
def getDropDownView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return self.getView(position, convertView, parent)
|
|
|
|
def toString(self) -> str:
|
|
return f"SpinnerAdapter@{hex(id(self))}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# WrapperListAdapter
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class WrapperListAdapter(Stub):
|
|
"""WrapperListAdapter — 包装列表适配器"""
|
|
|
|
def getWrappedAdapter(self) -> Optional[ListAdapter]:
|
|
return None
|
|
|
|
def getCount(self) -> int:
|
|
wrapped = self.getWrappedAdapter()
|
|
return wrapped.getCount() if wrapped else 0
|
|
|
|
def getItem(self, position: int) -> Optional[Any]:
|
|
wrapped = self.getWrappedAdapter()
|
|
return wrapped.getItem(position) if wrapped else None
|
|
|
|
def getItemId(self, position: int) -> int:
|
|
wrapped = self.getWrappedAdapter()
|
|
return wrapped.getItemId(position) if wrapped else position
|
|
|
|
def toString(self) -> str:
|
|
return f"WrapperListAdapter@{hex(id(self))}"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# HeaderViewListAdapter
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class HeaderViewListAdapter(WrapperListAdapter):
|
|
"""HeaderViewListAdapter — 页眉视图列表适配器"""
|
|
|
|
def __init__(self, wrappedAdapter: Optional[ListAdapter] = None):
|
|
super().__init__()
|
|
self._wrapped_adapter = wrappedAdapter
|
|
self._headers: List[Any] = []
|
|
self._footers: List[Any] = []
|
|
|
|
def getWrappedAdapter(self) -> Optional[ListAdapter]:
|
|
return self._wrapped_adapter
|
|
|
|
def addHeader(self, view: Any, data: Any = None, isSelectable: bool = True):
|
|
self._headers.append((view, data, isSelectable))
|
|
|
|
def addFooter(self, view: Any, data: Any = None, isSelectable: bool = True):
|
|
self._footers.append((view, data, isSelectable))
|
|
|
|
def removeHeader(self, view: Any) -> bool:
|
|
for i, (v, _, _) in enumerate(self._headers):
|
|
if v is view:
|
|
self._headers.pop(i)
|
|
return True
|
|
return False
|
|
|
|
def removeFooter(self, view: Any) -> bool:
|
|
for i, (v, _, _) in enumerate(self._footers):
|
|
if v is view:
|
|
self._footers.pop(i)
|
|
return True
|
|
return False
|
|
|
|
def getHeadersCount(self) -> int:
|
|
return len(self._headers)
|
|
|
|
def getFootersCount(self) -> int:
|
|
return len(self._footers)
|
|
|
|
def getCount(self) -> int:
|
|
count = len(self._headers) + len(self._footers)
|
|
if self._wrapped_adapter:
|
|
count += self._wrapped_adapter.getCount()
|
|
return count
|
|
|
|
def getItem(self, position: int) -> Optional[Any]:
|
|
if position < len(self._headers):
|
|
return self._headers[position][1]
|
|
offset = position - len(self._headers)
|
|
if self._wrapped_adapter and offset < self._wrapped_adapter.getCount():
|
|
return self._wrapped_adapter.getItem(offset)
|
|
footer_offset = offset - (self._wrapped_adapter.getCount() if self._wrapped_adapter else 0)
|
|
if 0 <= footer_offset < len(self._footers):
|
|
return self._footers[footer_offset][1]
|
|
return None
|
|
|
|
def getView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
if position < len(self._headers):
|
|
return self._headers[position][0]
|
|
offset = position - len(self._headers)
|
|
if self._wrapped_adapter and offset < self._wrapped_adapter.getCount():
|
|
return self._wrapped_adapter.getView(offset, convertView, parent)
|
|
footer_offset = offset - (self._wrapped_adapter.getCount() if self._wrapped_adapter else 0)
|
|
if 0 <= footer_offset < len(self._footers):
|
|
return self._footers[footer_offset][0]
|
|
return None
|
|
|
|
def toString(self) -> str:
|
|
return f"HeaderViewListAdapter(headers={len(self._headers)}, footers={len(self._footers)})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ArrayAdapter (扩展)
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ArrayAdapter(BaseAdapter):
|
|
"""ArrayAdapter — 数组适配器 (完整版)"""
|
|
|
|
def __init__(self, context: Any = None, resource: int = 0,
|
|
textViewResourceId: int = 0, objects: List[Any] = None):
|
|
super().__init__()
|
|
self._context = context
|
|
self._resource = resource
|
|
self._text_view_resource_id = textViewResourceId
|
|
self._objects: List[Any] = list(objects) if objects else []
|
|
self._drop_down_resource = resource
|
|
self._field_id = 0
|
|
self._filter: Optional[Any] = None
|
|
|
|
def add(self, obj: Any):
|
|
self._objects.append(obj)
|
|
self.notifyDataSetChanged()
|
|
|
|
def addAll(self, *objects: Any):
|
|
for obj in objects:
|
|
self._objects.append(obj)
|
|
self.notifyDataSetChanged()
|
|
|
|
def insert(self, obj: Any, index: int):
|
|
self._objects.insert(index, obj)
|
|
self.notifyDataSetChanged()
|
|
|
|
def remove(self, obj: Any):
|
|
if obj in self._objects:
|
|
self._objects.remove(obj)
|
|
self.notifyDataSetChanged()
|
|
|
|
def clear(self):
|
|
self._objects.clear()
|
|
self.notifyDataSetChanged()
|
|
|
|
def sort(self, comparator: Callable[[Any, Any], int]):
|
|
self._objects.sort(key=lambda x: x)
|
|
self.notifyDataSetChanged()
|
|
|
|
def getCount(self) -> int:
|
|
return len(self._objects)
|
|
|
|
def getItem(self, position: int) -> Optional[Any]:
|
|
if 0 <= position < len(self._objects):
|
|
return self._objects[position]
|
|
return None
|
|
|
|
def getPosition(self, item: Any) -> int:
|
|
try:
|
|
return self._objects.index(item)
|
|
except ValueError:
|
|
return ADAPTER_INVALID_POSITION
|
|
|
|
def setDropDownViewResource(self, resource: int):
|
|
self._drop_down_resource = resource
|
|
|
|
def getDropDownViewResource(self) -> int:
|
|
return self._drop_down_resource
|
|
|
|
def getContext(self) -> Any:
|
|
return self._context
|
|
|
|
def getFilter(self) -> Optional[Any]:
|
|
return self._filter
|
|
|
|
def createFromResource(context: Any, textArrayResId: int,
|
|
textViewResId: int) -> "ArrayAdapter":
|
|
return ArrayAdapter(context=context, resource=textViewResId)
|
|
|
|
def toString(self) -> str:
|
|
return f"ArrayAdapter(count={len(self._objects)})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# CursorAdapter (扩展)
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class CursorAdapter(BaseAdapter):
|
|
"""CursorAdapter — 游标适配器 (完整版)"""
|
|
|
|
FLAG_AUTO_REQUERY = 0x01
|
|
FLAG_REGISTER_CONTENT_OBSERVER = 0x02
|
|
|
|
def __init__(self, context: Any = None, cursor: Any = None,
|
|
flags: int = FLAG_AUTO_REQUERY):
|
|
super().__init__()
|
|
self._context = context
|
|
self._cursor = cursor
|
|
self._flags = flags
|
|
self._row_id_column = "_id"
|
|
self._count = 0
|
|
if cursor:
|
|
self._count = len(cursor) if hasattr(cursor, '__len__') else 0
|
|
|
|
def getCursor(self) -> Any:
|
|
return self._cursor
|
|
|
|
def setCursor(self, cursor: Any):
|
|
self._cursor = cursor
|
|
self._count = len(cursor) if cursor and hasattr(cursor, '__len__') else 0
|
|
self.notifyDataSetChanged()
|
|
|
|
def getCount(self) -> int:
|
|
return self._count
|
|
|
|
def getItem(self, position: int) -> Optional[Any]:
|
|
if self._cursor and 0 <= position < self._count:
|
|
if hasattr(self._cursor, '__getitem__'):
|
|
return self._cursor[position]
|
|
return self._cursor
|
|
return None
|
|
|
|
def getItemId(self, position: int) -> int:
|
|
if self._cursor and 0 <= position < self._count:
|
|
item = self.getItem(position)
|
|
if item and hasattr(item, 'get'):
|
|
return int(item.get(self._row_id_column, position))
|
|
return position
|
|
|
|
def getView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return self.newView(self._context, self._cursor, parent) if not convertView else convertView
|
|
|
|
def newView(self, context: Any, cursor: Any, parent: Any) -> Any:
|
|
return None
|
|
|
|
def bindView(self, view: Any, context: Any, cursor: Any):
|
|
pass
|
|
|
|
def changeCursor(self, cursor: Any):
|
|
self.setCursor(cursor)
|
|
|
|
def getFilterQueryProvider(self) -> Optional[Any]:
|
|
return None
|
|
|
|
def setFilterQueryProvider(self, provider: Any):
|
|
pass
|
|
|
|
def runQueryOnBackgroundThread(self, constraint: str) -> Any:
|
|
return self._cursor
|
|
|
|
def toString(self) -> str:
|
|
return f"CursorAdapter(count={self._count})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# SimpleCursorAdapter (扩展)
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class SimpleCursorAdapter(CursorAdapter):
|
|
"""SimpleCursorAdapter — 简单游标适配器 (完整版)"""
|
|
|
|
def __init__(self, context: Any = None, layout: int = 0,
|
|
cursor: Any = None, fromColumns: List[str] = None,
|
|
toViews: List[int] = None, flags: int = 0):
|
|
super().__init__(context=context, cursor=cursor, flags=flags)
|
|
self._layout = layout
|
|
self._from_columns = fromColumns or []
|
|
self._to_views = toViews or []
|
|
|
|
def getLayout(self) -> int:
|
|
return self._layout
|
|
|
|
def setViewText(self, view: Any, text: str):
|
|
pass
|
|
|
|
def setViewImage(self, view: Any, value: str):
|
|
pass
|
|
|
|
def getStringConversionColumn(self) -> int:
|
|
return 0
|
|
|
|
def setStringConversionColumn(self, column: int):
|
|
pass
|
|
|
|
def getViewBinder(self) -> Optional[Any]:
|
|
return None
|
|
|
|
def setViewBinder(self, viewBinder: Any):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"SimpleCursorAdapter(layout={self._layout})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# ResourceCursorAdapter (扩展)
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class ResourceCursorAdapter(CursorAdapter):
|
|
"""ResourceCursorAdapter — 资源游标适配器 (完整版)"""
|
|
|
|
def __init__(self, context: Any = None, layout: int = 0,
|
|
cursor: Any = None, flags: int = 0,
|
|
dropDownLayout: int = 0):
|
|
super().__init__(context=context, cursor=cursor, flags=flags)
|
|
self._layout = layout
|
|
self._drop_down_layout = dropDownLayout or layout
|
|
|
|
def setDropDownViewResource(self, dropDownLayout: int):
|
|
self._drop_down_layout = dropDownLayout
|
|
|
|
def getDropDownView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return self.newView(self._context, self._cursor, parent)
|
|
|
|
def toString(self) -> str:
|
|
return f"ResourceCursorAdapter(layout={self._layout})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# SimpleAdapter (扩展)
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class SimpleAdapter(BaseAdapter):
|
|
"""SimpleAdapter — 简单适配器 (完整版)"""
|
|
|
|
def __init__(self, context: Any = None, data: List[Dict[str, Any]] = None,
|
|
resource: int = 0, from_: List[str] = None,
|
|
to: List[int] = None):
|
|
super().__init__()
|
|
self._context = context
|
|
self._data = data or []
|
|
self._resource = resource
|
|
self._from_keys = from_ or []
|
|
self._to_ids = to or []
|
|
self._drop_down_resource = resource
|
|
|
|
def getCount(self) -> int:
|
|
return len(self._data)
|
|
|
|
def getItem(self, position: int) -> Optional[Dict[str, Any]]:
|
|
if 0 <= position < len(self._data):
|
|
return self._data[position]
|
|
return None
|
|
|
|
def getItemId(self, position: int) -> int:
|
|
return position
|
|
|
|
def getView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return convertView
|
|
|
|
def setDropDownViewResource(self, resource: int):
|
|
self._drop_down_resource = resource
|
|
|
|
def getDropDownView(self, position: int, convertView: Any, parent: Any) -> Any:
|
|
return convertView
|
|
|
|
def getContext(self) -> Any:
|
|
return self._context
|
|
|
|
def getData(self) -> List[Dict[str, Any]]:
|
|
return list(self._data)
|
|
|
|
def setData(self, data: List[Dict[str, Any]]):
|
|
self._data = list(data)
|
|
self.notifyDataSetChanged()
|
|
|
|
def toString(self) -> str:
|
|
return f"SimpleAdapter(count={len(self._data)})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# RecyclerView
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class RecyclerView(Stub):
|
|
"""RecyclerView — 循环视图"""
|
|
|
|
HORIZONTAL = 0
|
|
VERTICAL = 1
|
|
NO_POSITION = -1
|
|
NO_ID = -1
|
|
INVALID_TYPE = -1
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# RecyclerView.Adapter (扩展)
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class Adapter(BaseAdapter):
|
|
"""RecyclerView.Adapter — RecyclerView 适配器 (完整版)"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._has_stable_ids = False
|
|
self._state_restoration_policy = 0
|
|
self._observers: List[RecyclerView.AdapterDataObserver] = []
|
|
|
|
def onCreateViewHolder(self, parent: Any, viewType: int) -> "RecyclerView.ViewHolder":
|
|
raise NotImplementedError
|
|
|
|
def onBindViewHolder(self, holder: "RecyclerView.ViewHolder", position: int):
|
|
raise NotImplementedError
|
|
|
|
def getItemCount(self) -> int:
|
|
return 0
|
|
|
|
def getItemViewType(self, position: int) -> int:
|
|
return ADAPTER_IGNORE_ITEM_VIEW_TYPE
|
|
|
|
def setHasStableIds(self, hasStableIds: bool):
|
|
self._has_stable_ids = hasStableIds
|
|
|
|
def hasStableIds(self) -> bool:
|
|
return self._has_stable_ids
|
|
|
|
def onAttachedToRecyclerView(self, recyclerView: "RecyclerView"):
|
|
pass
|
|
|
|
def onDetachedFromRecyclerView(self, recyclerView: "RecyclerView"):
|
|
pass
|
|
|
|
def onViewAttachedToWindow(self, holder: "RecyclerView.ViewHolder"):
|
|
pass
|
|
|
|
def onViewDetachedFromWindow(self, holder: "RecyclerView.ViewHolder"):
|
|
pass
|
|
|
|
def onViewRecycled(self, holder: "RecyclerView.ViewHolder"):
|
|
pass
|
|
|
|
def onFailedToRecycleView(self, holder: "RecyclerView.ViewHolder") -> bool:
|
|
return False
|
|
|
|
def registerAdapterDataObserver(self, observer: "RecyclerView.AdapterDataObserver"):
|
|
self._observers.append(observer)
|
|
|
|
def unregisterAdapterDataObserver(self, observer: "RecyclerView.AdapterDataObserver"):
|
|
self._observers = [o for o in self._observers if o is not observer]
|
|
|
|
def notifyDataSetChanged(self):
|
|
for o in self._observers:
|
|
o.onChanged()
|
|
|
|
def notifyItemChanged(self, position: int):
|
|
for o in self._observers:
|
|
o.onItemRangeChanged(position, 1)
|
|
|
|
def notifyItemRangeChanged(self, positionStart: int, itemCount: int):
|
|
for o in self._observers:
|
|
o.onItemRangeChanged(positionStart, itemCount)
|
|
|
|
def notifyItemInserted(self, position: int):
|
|
for o in self._observers:
|
|
o.onItemRangeInserted(position, 1)
|
|
|
|
def notifyItemRangeInserted(self, positionStart: int, itemCount: int):
|
|
for o in self._observers:
|
|
o.onItemRangeInserted(positionStart, itemCount)
|
|
|
|
def notifyItemRemoved(self, position: int):
|
|
for o in self._observers:
|
|
o.onItemRangeRemoved(position, 1)
|
|
|
|
def notifyItemRangeRemoved(self, positionStart: int, itemCount: int):
|
|
for o in self._observers:
|
|
o.onItemRangeRemoved(positionStart, itemCount)
|
|
|
|
def notifyItemMoved(self, fromPosition: int, toPosition: int):
|
|
for o in self._observers:
|
|
o.onItemRangeMoved(fromPosition, toPosition, 1)
|
|
|
|
def getItemId(self, position: int) -> int:
|
|
return position
|
|
|
|
def toString(self) -> str:
|
|
return f"RecyclerView.Adapter(items={self.getItemCount()})"
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# RecyclerView.ViewHolder (扩展)
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class ViewHolder(Stub):
|
|
"""RecyclerView.ViewHolder — 视图持有者 (完整版)"""
|
|
|
|
def __init__(self, itemView: Any = None):
|
|
super().__init__()
|
|
self.itemView = itemView
|
|
self._adapter_position = RecyclerView.NO_POSITION
|
|
self._old_position = RecyclerView.NO_POSITION
|
|
self._item_id = RecyclerView.NO_ID
|
|
self._item_view_type = RecyclerView.INVALID_TYPE
|
|
self._is_recyclable = True
|
|
self._is_bound = False
|
|
|
|
def getAdapterPosition(self) -> int:
|
|
return self._adapter_position
|
|
|
|
def getOldPosition(self) -> int:
|
|
return self._old_position
|
|
|
|
def getItemId(self) -> int:
|
|
return self._item_id
|
|
|
|
def getItemViewType(self) -> int:
|
|
return self._item_view_type
|
|
|
|
def setIsRecyclable(self, recyclable: bool):
|
|
self._is_recyclable = recyclable
|
|
|
|
def isRecyclable(self) -> bool:
|
|
return self._is_recyclable
|
|
|
|
def setIsBound(self, bound: bool):
|
|
self._is_bound = bound
|
|
|
|
def isBound(self) -> bool:
|
|
return self._is_bound
|
|
|
|
def toString(self) -> str:
|
|
return f"ViewHolder(pos={self._adapter_position})"
|
|
|
|
def equals(self, other: Any) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return id(self) & 0x7FFFFFFF
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# RecyclerView.LayoutManager (扩展)
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class LayoutManager(Stub):
|
|
"""RecyclerView.LayoutManager — 布局管理器 (完整版)"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._child_count = 0
|
|
self._item_count = 0
|
|
self._auto_measure = True
|
|
|
|
def generateDefaultLayoutParams(self) -> Any:
|
|
return None
|
|
|
|
def onLayoutChildren(self, recycler: Any, state: Any):
|
|
pass
|
|
|
|
def getChildCount(self) -> int:
|
|
return self._child_count
|
|
|
|
def getItemCount(self) -> int:
|
|
return self._item_count
|
|
|
|
def setAutoMeasureEnabled(self, enabled: bool):
|
|
self._auto_measure = enabled
|
|
|
|
def isAutoMeasureEnabled(self) -> bool:
|
|
return self._auto_measure
|
|
|
|
def canScrollHorizontally(self) -> bool:
|
|
return False
|
|
|
|
def canScrollVertically(self) -> bool:
|
|
return False
|
|
|
|
def scrollToPosition(self, position: int):
|
|
pass
|
|
|
|
def smoothScrollToPosition(self, view: Any, state: Any, position: int):
|
|
pass
|
|
|
|
def computeVerticalScrollOffset(self, state: Any) -> int:
|
|
return 0
|
|
|
|
def computeVerticalScrollExtent(self, state: Any) -> int:
|
|
return 0
|
|
|
|
def computeVerticalScrollRange(self, state: Any) -> int:
|
|
return 0
|
|
|
|
def computeHorizontalScrollOffset(self, state: Any) -> int:
|
|
return 0
|
|
|
|
def computeHorizontalScrollExtent(self, state: Any) -> int:
|
|
return 0
|
|
|
|
def computeHorizontalScrollRange(self, state: Any) -> int:
|
|
return 0
|
|
|
|
def toString(self) -> str:
|
|
return f"LayoutManager(children={self._child_count})"
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# RecyclerView.AdapterDataObserver
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class AdapterDataObserver(Stub):
|
|
"""RecyclerView.AdapterDataObserver — 适配器数据观察者"""
|
|
|
|
def onChanged(self):
|
|
pass
|
|
|
|
def onItemRangeChanged(self, positionStart: int, itemCount: int):
|
|
pass
|
|
|
|
def onItemRangeInserted(self, positionStart: int, itemCount: int):
|
|
pass
|
|
|
|
def onItemRangeRemoved(self, positionStart: int, itemCount: int):
|
|
pass
|
|
|
|
def onItemRangeMoved(self, fromPosition: int, toPosition: int, itemCount: int):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"AdapterDataObserver@{hex(id(self))}"
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# RecyclerView.ItemDecoration
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class ItemDecoration(Stub):
|
|
"""RecyclerView.ItemDecoration — 项目装饰"""
|
|
|
|
def onDraw(self, canvas: Any, parent: "RecyclerView", state: Any):
|
|
pass
|
|
|
|
def onDrawOver(self, canvas: Any, parent: "RecyclerView", state: Any):
|
|
pass
|
|
|
|
def getItemOffsets(self, outRect: Any, view: Any,
|
|
parent: "RecyclerView", state: Any):
|
|
outRect.set(0, 0, 0, 0)
|
|
|
|
def toString(self) -> str:
|
|
return f"ItemDecoration@{hex(id(self))}"
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# RecyclerView.ItemAnimator
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class ItemAnimator(Stub):
|
|
"""RecyclerView.ItemAnimator — 项目动画器"""
|
|
|
|
def animateDisappearance(self, holder: ViewHolder, preInfo: Any,
|
|
postInfo: Any) -> bool:
|
|
return False
|
|
|
|
def animateAppearance(self, holder: ViewHolder, preInfo: Any,
|
|
postInfo: Any) -> bool:
|
|
return False
|
|
|
|
def animatePersistence(self, holder: ViewHolder, preInfo: Any,
|
|
postInfo: Any) -> bool:
|
|
return False
|
|
|
|
def animateChange(self, oldHolder: ViewHolder, newHolder: ViewHolder,
|
|
preInfo: Any, postInfo: Any) -> bool:
|
|
return False
|
|
|
|
def endAnimation(self, holder: ViewHolder):
|
|
pass
|
|
|
|
def endAnimations(self):
|
|
pass
|
|
|
|
def isRunning(self) -> bool:
|
|
return False
|
|
|
|
def dispatchAnimationsFinished(self):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"ItemAnimator@{hex(id(self))}"
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# RecyclerView.SmoothScroller
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class SmoothScroller(Stub):
|
|
"""RecyclerView.SmoothScroller — 平滑滚动器"""
|
|
|
|
def start(self, recyclerView: "RecyclerView", layoutManager: LayoutManager,
|
|
targetPosition: int):
|
|
pass
|
|
|
|
def stop(self):
|
|
pass
|
|
|
|
def isRunning(self) -> bool:
|
|
return False
|
|
|
|
def getTargetPosition(self) -> int:
|
|
return RecyclerView.NO_POSITION
|
|
|
|
def toString(self) -> str:
|
|
return f"SmoothScroller@{hex(id(self))}"
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# RecyclerView.OnScrollListener
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class OnScrollListener(Stub):
|
|
"""RecyclerView.OnScrollListener — 滚动监听器"""
|
|
|
|
SCROLL_STATE_IDLE = 0
|
|
SCROLL_STATE_DRAGGING = 1
|
|
SCROLL_STATE_SETTLING = 2
|
|
|
|
def onScrollStateChanged(self, recyclerView: "RecyclerView", newState: int):
|
|
pass
|
|
|
|
def onScrolled(self, recyclerView: "RecyclerView", dx: int, dy: int):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"OnScrollListener@{hex(id(self))}"
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._adapter: Optional[RecyclerView.Adapter] = None
|
|
self._layout_manager: Optional[RecyclerView.LayoutManager] = None
|
|
self._item_animator: Optional[RecyclerView.ItemAnimator] = None
|
|
self._scroll_listeners: List[RecyclerView.OnScrollListener] = []
|
|
self._item_decoration: Optional[RecyclerView.ItemDecoration] = None
|
|
|
|
def setAdapter(self, adapter: Adapter):
|
|
self._adapter = adapter
|
|
|
|
def getAdapter(self) -> Optional[Adapter]:
|
|
return self._adapter
|
|
|
|
def setLayoutManager(self, layoutManager: LayoutManager):
|
|
self._layout_manager = layoutManager
|
|
|
|
def getLayoutManager(self) -> Optional[LayoutManager]:
|
|
return self._layout_manager
|
|
|
|
def setItemAnimator(self, animator: ItemAnimator):
|
|
self._item_animator = animator
|
|
|
|
def getItemAnimator(self) -> Optional[ItemAnimator]:
|
|
return self._item_animator
|
|
|
|
def addItemDecoration(self, decoration: ItemDecoration, index: int = -1):
|
|
self._item_decoration = decoration
|
|
|
|
def addOnScrollListener(self, listener: OnScrollListener):
|
|
self._scroll_listeners.append(listener)
|
|
|
|
def removeOnScrollListener(self, listener: OnScrollListener):
|
|
self._scroll_listeners = [l for l in self._scroll_listeners if l is not listener]
|
|
|
|
def clearOnScrollListeners(self):
|
|
self._scroll_listeners.clear()
|
|
|
|
def scrollToPosition(self, position: int):
|
|
pass
|
|
|
|
def smoothScrollToPosition(self, position: int):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"RecyclerView(adapter={'set' if self._adapter else 'null'})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PagerAdapter
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PagerAdapter(Stub):
|
|
"""PagerAdapter — 页面适配器"""
|
|
|
|
POSITION_UNCHANGED = PAGER_POSITION_UNCHANGED
|
|
POSITION_NONE = PAGER_POSITION_NONE
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._observers: List[Any] = []
|
|
|
|
def getCount(self) -> int:
|
|
return 0
|
|
|
|
def instantiateItem(self, container: Any, position: int) -> Any:
|
|
return None
|
|
|
|
def destroyItem(self, container: Any, position: int, obj: Any):
|
|
pass
|
|
|
|
def isViewFromObject(self, view: Any, obj: Any) -> bool:
|
|
return False
|
|
|
|
def getPageTitle(self, position: int) -> Optional[str]:
|
|
return None
|
|
|
|
def getPageWidth(self, position: int) -> float:
|
|
return 1.0
|
|
|
|
def getItemPosition(self, obj: Any) -> int:
|
|
return PagerAdapter.POSITION_UNCHANGED
|
|
|
|
def startUpdate(self, container: Any):
|
|
pass
|
|
|
|
def finishUpdate(self, container: Any):
|
|
pass
|
|
|
|
def registerDataSetObserver(self, observer: Any):
|
|
self._observers.append(observer)
|
|
|
|
def unregisterDataSetObserver(self, observer: Any):
|
|
self._observers = [o for o in self._observers if o is not observer]
|
|
|
|
def notifyDataSetChanged(self):
|
|
for o in self._observers:
|
|
if hasattr(o, 'onChanged'):
|
|
o.onChanged()
|
|
|
|
def toString(self) -> str:
|
|
return f"PagerAdapter(count={self.getCount()})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# FragmentPagerAdapter
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class FragmentPagerAdapter(PagerAdapter):
|
|
"""FragmentPagerAdapter — Fragment 页面适配器"""
|
|
|
|
BEHAVIOR_SET_USER_VISIBLE_HINT = 0
|
|
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1
|
|
|
|
def __init__(self, fm: Any = None, behavior: int = BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT):
|
|
super().__init__()
|
|
self._fm = fm
|
|
self._behavior = behavior
|
|
self._fragments: Dict[int, Any] = {}
|
|
|
|
def getItem(self, position: int) -> Any:
|
|
raise NotImplementedError
|
|
|
|
def instantiateItem(self, container: Any, position: int) -> Any:
|
|
fragment = self.getItem(position)
|
|
self._fragments[position] = fragment
|
|
return fragment
|
|
|
|
def destroyItem(self, container: Any, position: int, obj: Any):
|
|
self._fragments.pop(position, None)
|
|
|
|
def isViewFromObject(self, view: Any, obj: Any) -> bool:
|
|
if hasattr(obj, 'getView'):
|
|
return obj.getView() is view
|
|
return False
|
|
|
|
def getPageTitle(self, position: int) -> Optional[str]:
|
|
return None
|
|
|
|
def getItemId(self, position: int) -> int:
|
|
return position
|
|
|
|
def toString(self) -> str:
|
|
return f"FragmentPagerAdapter(count={self.getCount()})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# FragmentStatePagerAdapter
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class FragmentStatePagerAdapter(FragmentPagerAdapter):
|
|
"""FragmentStatePagerAdapter — Fragment 状态页面适配器"""
|
|
|
|
def __init__(self, fm: Any = None, behavior: int = FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT):
|
|
super().__init__(fm=fm, behavior=behavior)
|
|
self._saved_states: Dict[int, Any] = {}
|
|
|
|
def saveState(self, position: int) -> Any:
|
|
state = self._saved_states.get(position)
|
|
self._fragments.pop(position, None)
|
|
return state
|
|
|
|
def restoreState(self, state: Any, loader: Any):
|
|
pass
|
|
|
|
def instantiateItem(self, container: Any, position: int) -> Any:
|
|
return super().instantiateItem(container, position)
|
|
|
|
def destroyItem(self, container: Any, position: int, obj: Any):
|
|
state = self.saveState(position)
|
|
if state:
|
|
self._saved_states[position] = state
|
|
super().destroyItem(container, position, obj)
|
|
|
|
def toString(self) -> str:
|
|
return f"FragmentStatePagerAdapter(count={self.getCount()})"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# PagerTitleStrip / PagerTabStrip
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class PagerTitleStrip(Stub):
|
|
"""PagerTitleStrip — 页面标题条"""
|
|
|
|
def __init__(self, context: Any = None):
|
|
super().__init__()
|
|
self._text_spacing = 16
|
|
self._nonprimary_alpha = 0.6
|
|
self._current_page = 0
|
|
self._adapter: Optional[PagerAdapter] = None
|
|
|
|
def setAdapter(self, adapter: PagerAdapter):
|
|
self._adapter = adapter
|
|
|
|
def getAdapter(self) -> Optional[PagerAdapter]:
|
|
return self._adapter
|
|
|
|
def setTextSpacing(self, spacingPixels: int):
|
|
self._text_spacing = spacingPixels
|
|
|
|
def getTextSpacing(self) -> int:
|
|
return self._text_spacing
|
|
|
|
def updateTitle(self, position: int, adapter: PagerAdapter):
|
|
self._current_page = position
|
|
|
|
def requestLayout(self):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"PagerTitleStrip(page={self._current_page})"
|
|
|
|
|
|
class PagerTabStrip(PagerTitleStrip):
|
|
"""PagerTabStrip — 页面标签条"""
|
|
|
|
def __init__(self, context: Any = None):
|
|
super().__init__(context=context)
|
|
self._tab_indicator_color = 0
|
|
self._tab_spacing = 8
|
|
self._draw_full_underline = False
|
|
self._underline_height = 2
|
|
self._tab_padding = 16
|
|
|
|
def setTabIndicatorColor(self, color: int):
|
|
self._tab_indicator_color = color
|
|
|
|
def getTabIndicatorColor(self) -> int:
|
|
return self._tab_indicator_color
|
|
|
|
def setDrawFullUnderline(self, draw: bool):
|
|
self._draw_full_underline = draw
|
|
|
|
def isDrawFullUnderline(self) -> bool:
|
|
return self._draw_full_underline
|
|
|
|
def setUnderlineHeight(self, height: int):
|
|
self._underline_height = height
|
|
|
|
def getUnderlineHeight(self) -> int:
|
|
return self._underline_height
|
|
|
|
def setTabPadding(self, padding: int):
|
|
self._tab_padding = padding
|
|
|
|
def getTabPadding(self) -> int:
|
|
return self._tab_padding
|
|
|
|
def toString(self) -> str:
|
|
return f"PagerTabStrip(page={self._current_page})" |