У меня есть действие с макетом ограничений с элементом EditText, а затем двумя фреймами, в которые я добавляю RowSupportFragment и ВертикальныйSupportGridFragment программно на основе вызова API. Я получаю данные, и они отображаются на экране. Однако вы не можете перемещаться вверх/вниз. Я не знаю, п о ч е м у о н н е р а б о т а е т д о л ж н ы м о б р а з о м . < / p > < b r / > В о т м о й X M L - ф а й л м а к е т а : < / p > < b r / > < c o d e > & l t ; a n d r o i d x . c o n s t r a i n t l a y o u t . w i d g e t . C o n s t r a i n t L a y o u t x m l n s : a n d r o i d = & q u o t ; h t t p : / / s c h e m a s . a n d r o i d . c o m / a p k / r e s / a n d r o i d & q u o t ; < b r / > x m l n s : t o o l s = & q u o t ; h t t p : / / s c h e m a s . a n d r o i d . c o m / t o o l s & q u o t ; < b r / > a n d r o i d : i d = & q u o t ; @ + i d / s e a r c h L a y o u t & q u o t ; < b r / > a n d r o i d : b a c k g r o u n d = & q u o t ; # 0 0 0 0 0 0 & q u o t ; < b r / > a n d r o i d : l a y o u t _ w i d t h = & q u o t ; m a t c h _ p a r e n t & q u o t ; < b r / > a n d r o i d : l a y o u t _ h e i g h t = & q u o t ; m a t c h _ p a r e n t & q u o t ; < b r / > x m l n s : a p p = & q u o t ; h t t p : / / s c h e m a s . a n d r o i d . c o m / a p k / r e s - a u t o & q u o t ; < b r / > & g t ; < b r / > & l t ; T e x t V i e w < b r / > a n d r o i d : i d = & q u o t ; @ + i d / s e a r c h T e x t V i e w & q u o t ; < b r / > a n d r o i d : l a y o u t _ w i d t h = & q u o t ; m a t c h _ p a r e n t & q u o t ; < b r / > a n d r o i d : l a y o u t _ h e i g h t = & q u o t ; w r a p _ c o n t e n t & q u o t ; < b r / > a n d r o i d : l a y o u t _ m a r g i n S t a r t = & q u o t ; 1 6 d p & q u o t ; < b r / > a n d r o i d : l a y o u t _ m a r g i n T o p = & q u o t ; 1 6 d p & q u o t ; < b r / > a n d r o i d : t e x t = & q u o t ; S e a r c h & q u o t ; < b r / > a n droid:textColor="@color/white"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
class SearchVideoGridFragment(
val onItemClick: (index: Int?, item: SearchResultsVideoHitData) -> Unit,
val onItemSelect: (index: Int?, item: SearchResultsVideoHitData, size: Int?) -> Unit
): VerticalGridSupportFragment(), OnItemViewSelectedListener,
OnItemViewClickedListener {
private var mainAdapter: ArrayObjectAdapter? = null
private var firstItem: SearchVideoItemCardPresenter? = null
private val ZOOM_FACTOR: Int = FocusHighlight.ZOOM_FACTOR_NONE
private val COLUMNS = 6
private val deviceWidth = DisplayMetrics().widthPixels
private val cellWidth = deviceWidth / COLUMNS
private val cellHeight = cellWidth * 9 / 16
var results: List by Delegates.observable(emptyList()){ _, oldValue, newValue ->
if (oldValue != newValue){
Log.d("SearchVideoGridFragment", "results changed")
displayData()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("SearchVideoGridFragment", "onCreate")
setupAdapter()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
Log.d("SearchVideoGridFragment", "onCreateView")
val view = super.onCreateView(inflater, container, savedInstanceState)
applyConstraints(view)
return view
}
override fun onDestroy() {
super.onDestroy()
clearData()
}
override fun onDestroyView() {
super.onDestroyView()
clearData()
}
private fun applyConstraints(view: View?) {
Log.d("SearchVideoGridFragment", "applyConstraints: $view")
}
private fun setupAdapter() {
val videoGridPresenter =
CustomVerticalGridPresenter(ZOOM_FACTOR, false, 100, 1, 0,0)
videoGridPresenter.numberOfColumns = COLUMNS
videoGridPresenter.shadowEnabled = false
val itemDecoration = VerticalSpaceItemDecoration(200)
videoGridPresenter.gridView?.post {
videoGridPresenter.gridView?.addItemDecoration(itemDecoration)
}
setOnItemViewSelectedListener(this)
onItemViewClickedListener = this
gridPresenter = videoGridPresenter
val sideInfoCardPresenter =
SearchVideoItemCardPresenter(requireActivity())
mainAdapter = ArrayObjectAdapter(sideInfoCardPresenter)
adapter = mainAdapter
applyConstraints(videoGridPresenter.gridView?.rootView)
}
private fun displayData(){
mainAdapter?.clear()
mainAdapter?.addAll(0, results)
if (firstItem == null){
firstItem = mainAdapter?.getPresenter(0) as SearchVideoItemCardPresenter
}
}
private fun clearData(){
mainAdapter?.clear()
}
override fun onItemSelected(
itemViewHolder: Presenter.ViewHolder?,
item: Any?,
rowViewHolder: RowPresenter.ViewHolder?,
row: Row?
) {
Log.d("SearchVideoGridFragment", "onItemSelected")
val position: Int? = mainAdapter?.indexOf(item)
if (item is SearchResultsVideoHitData){
onItemSelect.invoke(position, item, mainAdapter?.size()?:0)
}
}
override fun onItemClicked(
itemViewHolder: Presenter.ViewHolder?,
item: Any?,
rowViewHolder: RowPresenter.ViewHolder?,
row: Row?
) {
Log.d("SearchVideoGridFragment", "onItemClicked")
val position: Int? = mainAdapter?.indexOf(item)
if (item is SearchResultsVideoHitData){
onItemClick.invoke(position, item)
} else {
Log.d("SearchVideoGridFragment", "item is: "+ item!!::class.simpleName)
}
}
}
Поскольку rowFragment представляет собой одну строку, я могу вручную управлять фокусом между строкой и searchEditText, но я действительно не хочу делать это таким образом .
У меня есть действие с макетом ограничений с элементом EditText, а затем двумя фреймами, в которые я добавляю RowSupportFragment и ВертикальныйSupportGridFragment программно на основе вызова API. Я получаю данные, и они отображаются на экране. Однако вы не можете перемещаться вверх/вниз. Я не знаю, п о ч е м у о н н е р а б о т а е т д о л ж н ы м о б р а з о м . < / p > < b r / > В о т м о й X M L - ф а й л м а к е т а : < / p > < b r / > < c o d e > & l t ; a n d r o i d x . c o n s t r a i n t l a y o u t . w i d g e t . C o n s t r a i n t L a y o u t x m l n s : a n d r o i d = & q u o t ; h t t p : / / s c h e m a s . a n d r o i d . c o m / a p k / r e s / a n d r o i d & q u o t ; < b r / > x m l n s : t o o l s = & q u o t ; h t t p : / / s c h e m a s . a n d r o i d . c o m / t o o l s & q u o t ; < b r / > a n d r o i d : i d = & q u o t ; @ + i d / s e a r c h L a y o u t & q u o t ; < b r / > a n d r o i d : b a c k g r o u n d = & q u o t ; # 0 0 0 0 0 0 & q u o t ; < b r / > a n d r o i d : l a y o u t _ w i d t h = & q u o t ; m a t c h _ p a r e n t & q u o t ; < b r / > a n d r o i d : l a y o u t _ h e i g h t = & q u o t ; m a t c h _ p a r e n t & q u o t ; < b r / > x m l n s : a p p = & q u o t ; h t t p : / / s c h e m a s . a n d r o i d . c o m / a p k / r e s - a u t o & q u o t ; < b r / > & g t ; < b r / > & l t ; T e x t V i e w < b r / > a n d r o i d : i d = & q u o t ; @ + i d / s e a r c h T e x t V i e w & q u o t ; < b r / > a n d r o i d : l a y o u t _ w i d t h = & q u o t ; m a t c h _ p a r e n t & q u o t ; < b r / > a n d r o i d : l a y o u t _ h e i g h t = & q u o t ; w r a p _ c o n t e n t & q u o t ; < b r / > a n d r o i d : l a y o u t _ m a r g i n S t a r t = & q u o t ; 1 6 d p & q u o t ; < b r / > a n d r o i d : l a y o u t _ m a r g i n T o p = & q u o t ; 1 6 d p & q u o t ; < b r / > a n d r o i d : t e x t = & q u o t ; S e a r c h & q u o t ; < b r / > a n droid:textColor="@color/white" android:textSize="24sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
Вот мой котлин-файл активности: [code]class SearchActivity: AppCompatActivity(), SearchView { private lateinit var binding: ActivitySearchBinding private val disposables = CompositeDisposable() private val presenter = SearchPresenter() private var fManager: FragmentManager? = null private var fragmentTransaction: FragmentTransaction? = null
private var channelList: List? = emptyList() private var videoList: List? = emptyList() private var channelFragment: SearchChannelRowFragment? = null private var videoFragment: SearchVideoGridFragment? = null
override fun onCreate(bundle: Bundle?) { super.onCreate(bundle)
private fun showKeyboard(view: View) { val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT) }
private fun setupEditTextListeners(et: EditText) { et.onFocusChangeListener = View.OnFocusChangeListener { view, hasFocus -> if (hasFocus) { showKeyboard(view) } } et.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { if (s.toString().length > 2) { val searchBody = SearchRequestBody(q = s.toString()) Log.d("SearchActivity", "Search query: ${searchBody.q}") presenter.getSearchResultsData(searchBody) } }
companion object { fun launchActivity( activity: Activity, ) { val intent = Intent(activity, SearchActivity::class.java) ActivityCompat.startActivity( activity, intent, null ) } } } [/code] Вот мой RowSupportFragment: [code]class SearchChannelRowFragment( var onItemClick: (String?, String?, String?) -> Unit?, var onItemSelect: (Int, Int) -> Unit? ): RowsSupportFragment(), OnItemViewSelectedListener, OnItemViewClickedListener {
private var channelList: List? = null
private var mainAdapter: ArrayObjectAdapter? = null private var channelListAdapter: ArrayObjectAdapter? = null
private var firstItem: SearchChannelItemCardPresenter? = null private var firstItemPos: Int? = 0
var results: List by Delegates.observable(emptyList()){ _, oldValue, newValue -> if (oldValue != newValue){ Log.d("SearchVideoGridFragment", "results changed: $oldValue | $newValue") results = newValue displayData() } }
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
val aa = CustomListRowPresenter(FocusHighlight.ZOOM_FACTOR_NONE, false) aa.shadowEnabled = false aa.selectEffectEnabled = false mainAdapter = ArrayObjectAdapter(aa)
setAlignment(60)
setOnItemViewSelectedListener { itemViewHolder, item, rowViewHolder, row -> Log.d("Item", "Item: $item") val listRow = row as ListRow
val currentRowAdapter = listRow.adapter as ArrayObjectAdapter val itemPos = currentRowAdapter.indexOf(item) if (currentRowAdapter == channelListAdapter) { firstItemPos = itemPos //Log.d("itemPos", "ItemPos: $itemPos") } onItemSelect.invoke(itemPos, listRow.adapter?.size() ?: 0) } setOnItemViewClickedListener { itemViewHolder, item, rowViewHolder, row -> Log.d("setOnClickListener", "setOnClickListener $item") val listRow = row as ListRow val currentRowAdapter = listRow.adapter as ArrayObjectAdapter val itemPos = currentRowAdapter.indexOf(item) if (item is HostData){ Log.d("setOnClickListener", "setOnClickListener: ${item.title}") // Convert SearchResultsChannelHitData to HostData to pass // to HostDetailActivity.launchActivity activity?.let { HostDetailActivity.launchActivity(it, item, itemPos ) } }else if (item is AbsoluteRowData){ onItemClick.invoke(item.videoUrl, item.title, item.imageUrl) }else if (item is RecentlyAddedRowData){ Log.e("recent item", "Item") onItemClick.invoke(item.mediaUrl, item.title, item.imageUrl) } } }
override fun onDestroy() { super.onDestroy() mainAdapter?.clear() clearData() }
override fun onDestroyView() { super.onDestroyView() mainAdapter?.clear() clearData() }
override fun onItemSelected(itemViewHolder: Presenter.ViewHolder?, item: Any?, rowViewHolder: RowPresenter.ViewHolder?, row: Row?) { val position: Int? = mainAdapter?.indexOf(item) if (item is SearchResultsChannelHitData){ onItemSelect.invoke(position?:0, mainAdapter?.size() ?: 0) } }
override fun onItemClicked( itemViewHolder: Presenter.ViewHolder?, item: Any?, rowViewHolder: RowPresenter.ViewHolder?, row: Row? ) { Log.d("SearchChannelRowFragment", "onItemClicked") if (item is SearchResultsVideoHitData && item.productId.isNullOrEmpty().not()){ Log.d("ProductID", "ProductID: ${item.productId}") activity?.let { PaidMediaActivity.launchActivity(it,null, item.productId, item.document?.thumbnailUrl) } }else if (item is AbsoluteRowData){ onItemClick.invoke(item.videoUrl, item.title, item.imageUrl) }else if (item is RecentlyAddedRowData){ Log.e("recent item", "Item") onItemClick.invoke(item.mediaUrl, item.title, item.imageUrl) } }
private fun displayData(){ Log.d("SearchChannelRowFragment", "displayData run ${results.size}") // We need to mutate results into HostData objects var hostDataList = mutableListOf() for (result in results) { val hostData = HostData() hostData.title = result.title hostData.teaserText = "" hostData.nid = result.document?.externalId hostData.imageUrl = result.document?.imageUrl hostDataList.add(hostData) } mainAdapter?.clear() channelListAdapter?.clear() channelListAdapter = ArrayObjectAdapter(SearchChannelItemCardPresenter(requireContext())) channelListAdapter?.addAll(0 ,hostDataList)
if (channelListAdapter?.size() != 0){ mainAdapter?.add(ListRow(HeaderItem("Channels"), channelListAdapter)) }
/* if(absoluteItemList.isNullOrEmpty().not()) { val headerFeaturedItem = HeaderItem("Recent Clips") absoluteItemAdapter?.addAll(0, absoluteItemList) if (absoluteItemAdapter?.size() != 0){ mainAdapter?.add(ListRow(headerFeaturedItem, absoluteItemAdapter)) } } */
private fun clearData(){ channelList = emptyList() mainAdapter?.clear() } } [/code] Вот мой UpperSupportGridFragment: [code]class SearchVideoGridFragment( val onItemClick: (index: Int?, item: SearchResultsVideoHitData) -> Unit, val onItemSelect: (index: Int?, item: SearchResultsVideoHitData, size: Int?) -> Unit ): VerticalGridSupportFragment(), OnItemViewSelectedListener, OnItemViewClickedListener {
private var mainAdapter: ArrayObjectAdapter? = null
private var firstItem: SearchVideoItemCardPresenter? = null private val ZOOM_FACTOR: Int = FocusHighlight.ZOOM_FACTOR_NONE private val COLUMNS = 6 private val deviceWidth = DisplayMetrics().widthPixels private val cellWidth = deviceWidth / COLUMNS private val cellHeight = cellWidth * 9 / 16
var results: List by Delegates.observable(emptyList()){ _, oldValue, newValue -> if (oldValue != newValue){ Log.d("SearchVideoGridFragment", "results changed") displayData() } }
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.d("SearchVideoGridFragment", "onCreate") setupAdapter() }
private fun displayData(){ mainAdapter?.clear() mainAdapter?.addAll(0, results)
if (firstItem == null){ firstItem = mainAdapter?.getPresenter(0) as SearchVideoItemCardPresenter } }
private fun clearData(){ mainAdapter?.clear() }
override fun onItemSelected( itemViewHolder: Presenter.ViewHolder?, item: Any?, rowViewHolder: RowPresenter.ViewHolder?, row: Row? ) { Log.d("SearchVideoGridFragment", "onItemSelected") val position: Int? = mainAdapter?.indexOf(item) if (item is SearchResultsVideoHitData){ onItemSelect.invoke(position, item, mainAdapter?.size()?:0) } }
override fun onItemClicked( itemViewHolder: Presenter.ViewHolder?, item: Any?, rowViewHolder: RowPresenter.ViewHolder?, row: Row? ) { Log.d("SearchVideoGridFragment", "onItemClicked") val position: Int? = mainAdapter?.indexOf(item) if (item is SearchResultsVideoHitData){ onItemClick.invoke(position, item) } else { Log.d("SearchVideoGridFragment", "item is: "+ item!!::class.simpleName) } }
} [/code] Поскольку rowFragment представляет собой одну строку, я могу вручную управлять фокусом между строкой и searchEditText, но я действительно не хочу делать это таким образом .