So I created a carousel type app with pictures in them. I want to record the number of swipes the user does and have it displayed on a counter.
*The counter is next to "number of swipes"
Here is what I got so far in the code
class MainFragment: Fragment() {
// private lateinit var manager: RecyclerView.LayoutManager
private lateinit var viewPager: ViewPager2
private var counter: Int = 0
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding: MainFragmentBinding = DataBindingUtil.inflate(
inflater,
R.layout.main_fragment,
container, false)
viewPager = binding.imageSlider
val data: MutableList<CarouselItem> = ArrayList()
data.add(CarouselItem(1, bcw_65, "First"))
data.add(CarouselItem(2, bcw_66, "Second"))
data.add(CarouselItem(3, bcw_67, "Third"))
data.add(CarouselItem(4, bcw_68, "Fourth"))
data.add(CarouselItem(5, bcw_69, "Fifth"))
data.add(CarouselItem(6, bcw_70, "Sixth"))
data.add(CarouselItem(2, bcw_71, "Seventh"))
viewPager.adapter = CarouselItemAdapter(data, viewPager)
viewPager.clipToPadding = false
viewPager.clipChildren = false
viewPager.offscreenPageLimit = 3
viewPager.getChildAt(0).overScrollMode = RecyclerView.OVER_SCROLL_NEVER
val compositePageTransformer = CompositePageTransformer()
compositePageTransformer.addTransformer(MarginPageTransformer(30))
compositePageTransformer.addTransformer { page, position ->
val r = 1 - abs(position)
page.scaleY = 0.85f + r * 0.25f
}
viewPager.setPageTransformer(compositePageTransformer)
// binding.imageSlider.setOnTouchListener{}
binding.imageSlider.setOnTouchListener { v, event ->
counter++
Log.d(TAG, "onCreateView: Swipe Recorded")
true
}
binding.counterView.text = counter.toString()
return binding.root
}
}
I have tried a few things, but it still doesn't seem to really work. Any ideas will be greatly appreciated.
Add a ViewPager2.OnPageChangeCallback to your pager:
class MainFragment: Fragment() {
private lateinit var viewPager: ViewPager2
private var counter: Int = 0
private var pageChangeCallback: ViewPager2.OnPageChangeCallback? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
...
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
counter++
binding.counterView.text = counter.toString()
}
}.also { pageChangeCallback = it })
...
}
override fun onDestroyView() {
super.onDestroyView()
viewPager.unregisterOnPageChangeCallback(pageChangeCallback!!)
pageChangeCallback = null
}
}
Related
I have just started working with leanback. I want to add my custom layout to this class.please help me...
`class CustomHeadersFragment: HeadersSupportFragment(),OnHeaderClickedListener {
lateinit var adapter: ArrayObjectAdapter
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// customSetBackground(R.color.fastlane_background)
setOnHeaderClickedListener(this)
setHeaderAdapter()
presenterSelector
}
private fun setHeaderAdapter() {
adapter = ArrayObjectAdapter()
val fragments: LinkedHashMap<Int, CustomRowsFragment> =
(activity as MainActivity?)?.getFragments()!!
var id = 0
for (i in 0 until fragments.size) {
val header = HeaderItem(id.toLong(), "Category $i")
val innerAdapter = ArrayObjectAdapter()
innerAdapter.add(fragments[i])
adapter.add(id, ListRow(header, innerAdapter))
id++
}
setAdapter(adapter)
}`
this is my rows fragment
`class CustomRowsFragment : RowsSupportFragment() {
private var rowsAdapter: ArrayObjectAdapter? = null
private var cardPresenter: Presenter? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val v = super.onCreateView(inflater, container, savedInstanceState)
return v
}`
I want to create a variable that holds my View LinearLayoutManager, but I'm using bottom nav bar and I got fragments instead of views and I don't know how to get the context.
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
val cardsRecyclerView : RecyclerView = binding.rvCards
val homeLayout : ConstraintLayout = binding.homeLayout
homeViewModel.text.observe(viewLifecycleOwner) {
val linearLayout = LinearLayoutManager(/*here i can't get the context*/)
val adapter = RecyclerAdapter(mutableListOf("blue", "orange", "pink", "gray"), mutableListOf(6092049204821920, 3958271029482085, 8375027502862095, 2957285928029573)
, mutableListOf(16,7,13,24), mutableListOf(7,4,1,10), mutableListOf("Eduard Radu", "John Doe", "Ayman Achalhe", "Mike Rivera"))
cardsRecyclerView.layoutManager = linearLayout
cardsRecyclerView.adapter = adapter
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
You can use activity or requireActivity
I have two fragments and want to open second fragment (WordFragment) when pressing button of the first one(SearchFragment) by Bundle. But Fragment shwos default data instead of the passed one.
ClickListener in First Fragment:
searchDefAdapter = SearchDefAdapter(
object : SearchDefAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
val bundle = Bundle()
val arr = arrayOf("word", "слово", "I give you my word")
bundle.putStringArray(INFO_BUNDLE_ID, arr)
val wordFragment = WordFragment()
wordFragment.arguments = bundle
parentFragmentManager.beginTransaction().apply {
replace(R.id.searchFragment, WordFragment())
commit()
}
}
},
object : SearchDefAdapter.OnItemClickListener {
override fun onItemClick(position: Int) {
//viewModel.saveWord(position)
}
}
)
Second Fragment:
class WordFragment : Fragment() {
private var _binding: FragmentWordBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentWordBinding.inflate(inflater, container, false)
val view = binding.root
arguments?.let {
val translation = it.getStringArray(INFO_BUNDLE_ID)
if (translation != null){
binding.wordTitleTv.text = translation[0]
binding.translationTv.text = translation[1]
binding.exampleTv.text = translation[2]
}
}
return view
}
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
}
this is because you create new WordFragment here replace(R.id.searchFragment, WordFragment()) instead of putting the one you added the bundle to it.
I have a fragment which happens to be the host fragment with a view pager to three other fragment. I want to access the view pager in the parent fragment from the children so I can manage the currentItem property on button click but using parentFragment is not working.
Parent Fragment
class ClientFragment : DaggerFragment() {
lateinit var adapter: ViewPagerAdapter
private lateinit var nextBtn: Button
private lateinit var progressBar: ProgressBar
private val title by lazy {
getName()
}
val clientManagementViewPager by lazy {
(client_management_included_viewPager as? ViewPager2)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_client, container, false)
}
override fun onResume() {
super.onResume()
setupViewPager()
val toolbar = (client_management_toolbar as Toolbar)
toolbar.setTitleTextColor(
ContextCompat.getColor(
requireContext(),
R.color.colorPrimaryDark
)
)
val navController = Navigation.findNavController(client_management_appBar)
NavigationUI.setupWithNavController(toolbar, navController)
nextBtn = client_account_next_btn2.findViewById(R.id.btn)
progressBar = client_account_next_btn2.findViewById(R.id.progress_bar)
val nextBtnBackground =
ContextCompat.getDrawable(requireContext(), R.drawable.rounded_corner_background)
nextBtnBackground?.colorFilter = PorterDuffColorFilter(
ContextCompat.getColor(requireContext(), R.color.colorPrimary),
PorterDuff.Mode.SRC_IN
)
nextBtn.text = getString(R.string.next)
nextBtn.background = nextBtnBackground
nextBtn.setTextColor(ContextCompat.getColor(requireContext(), R.color.colorAccent))
nextBtn.setOnClickListener {
clientManagementViewPager?.currentItem = 1
}
clientManagementViewPager?.registerOnPageChangeCallback(object :ViewPager2.OnPageChangeCallback(){
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
when(position){
1 -> nextBtn.hide()
0-> nextBtn.show()
}
}
})
}
}
Child Fragment
class ClientAccountFragment : DaggerFragment(){
private val title by lazy {
getName()
}
private lateinit var nextBtn: Button
private lateinit var progressBar: ProgressBar
#Inject
lateinit var viewModelProviderFactory: ViewModelFactory
private val authViewModel: AuthViewModel by lazy {
ViewModelProvider(this, viewModelProviderFactory).get(AuthViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_client_account, container, false)
}
override fun onResume() {
super.onResume()
(parentFragment as? ClientFragment)?.setItem(2)
nextBtn.setOnClickListener {
Log.i(title, "here2")
(parentFragment as? ClientFragment)?.clientManagementViewPager?.currentItem = 1
}
}
}
I was able to fix this with following lines
val navHostFragment = requireActivity().supportFragmentManager.fragments[0] as NavHostFragment
val parent = navHostFragment.childFragmentManager.primaryNavigationFragment as ClientFragment
I have an activity that hosts both fragments called SourceFragment and DestinationFragment. The SourceFragment contains a RecyclerView and the DestinationFragment contains a ViewPager. I've been using the fragment manager to swap back and forth between the Source and Destination fragment.
Issue:
The return transition works normally as long as I don't swipe to a different view on the ViewPager. To resolve this I overrode the onMapSharedElements in the DestinationFragment and the SourceFragment to make sure the views match each other when the view pager is swiped.
For some reason swiping and returning to the SourceFragment doesn't work and no transition animation happens. I even debugged the onMapSharedElements functions to make sure that the views mapped correctly.
This is what I'm trying to implement.
My implementation
I've provided the code below for the fragments in question but here is the repo to my implementation. Been itching my head for a week now trying to figure this out hopefully I can get some insight as to why this is happening.
SourceFragment:
class SourceFragment : Fragment() {
private lateinit var sharedViewModel: SharedViewModel
private lateinit var itemRecyclerView: RecyclerView
private lateinit var adapter: SourceAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setExitSharedElementCallback(object : SharedElementCallback() {
override fun onMapSharedElements(names: MutableList<String>?, sharedElements: MutableMap<String, View>?) {
val view = itemRecyclerView.findViewHolderForAdapterPosition(sharedViewModel.currentPos)
?.itemView?.findViewById<TextView>(R.id.source_text)
val item = sharedViewModel.itemList[sharedViewModel.currentPos]
if (view == null) return
names?.clear()
sharedElements?.clear()
names?.add(item)
sharedElements?.put(item, view)
}
})
sharedViewModel = ViewModelProviders.of(requireActivity()).get(SharedViewModel::class.java)
adapter = SourceAdapter(object : onClickItem {
override fun onClick(position: Int, view: View) {
// Save the position of the item that was clicked.
sharedViewModel.currentPos = position
// Setup shared element transition
val transitionName = ViewCompat.getTransitionName(view) ?: ""
// Start fragment transaction along with shared element transition.
fragmentManager?.apply {
beginTransaction()
.setReorderingAllowed(true)
.addSharedElement(view, transitionName)
.replace(
R.id.fragment_container,
DestinationFragment(),
DestinationFragment::class.java.simpleName
)
.addToBackStack(null)
.commit()
}
}
})
val list = sharedViewModel.itemList
adapter.submitList(list)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.source_layout, container, false)
postponeEnterTransition()
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Setup recycler view here
itemRecyclerView = item_recycler_view
itemRecyclerView.layoutManager = GridLayoutManager(requireContext(), 2)
itemRecyclerView.adapter = adapter
// Start enter transition on pre draw.
itemRecyclerView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
itemRecyclerView.viewTreeObserver.removeOnPreDrawListener(this)
startPostponedEnterTransition()
return true
}
})
// Scroll to the position of the item that was selected in the Destination Fragment.
itemRecyclerView.addOnLayoutChangeListener { p0, p1, p2, p3, p4, p5, p6, p7, p8 ->
val layoutMan = itemRecyclerView.layoutManager
val viewAtPos = layoutMan?.findViewByPosition(sharedViewModel.currentPos)
if (viewAtPos == null ||
layoutMan.isViewPartiallyVisible(viewAtPos, false, true)
) {
itemRecyclerView.post {
layoutMan?.scrollToPosition(sharedViewModel.currentPos)
}
}
}
}
DestinationFragment
class DestinationFragment : Fragment(), MainActivityListener {
lateinit var sharedViewModel: SharedViewModel
lateinit var destPager : ViewPager
lateinit var itemAdapter : ItemPagerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
postponeEnterTransition()
setEnterSharedElementCallback(object : androidx.core.app.SharedElementCallback(){
override fun onMapSharedElements(names: MutableList<String>?, sharedElements: MutableMap<String, View>?) {
val item = sharedViewModel.itemList[destPager.currentItem]
val itemView = (itemAdapter.instantiateItem(destPager, destPager.currentItem) as Fragment).view?.findViewById<TextView>(R.id.item_fragment_textview) as View
names?.clear()
names?.add(item)
sharedElements?.clear()
sharedElements?.put(item, itemView)
}
})
sharedElementEnterTransition = TransitionInflater.from(requireContext()).inflateTransition(android.R.transition.move)
sharedViewModel = ViewModelProviders.of(requireActivity()).get( SharedViewModel::class.java)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.destination_layout, container ,false)
}
override fun onBackPressed(): Boolean {
sharedViewModel.currentPos = destPager.currentItem
return false
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
destPager = destination_pager
itemAdapter = ItemPagerAdapter(sharedViewModel.itemList, childFragmentManager)
destination_pager.adapter = itemAdapter
destination_pager.currentItem = sharedViewModel.currentPos
}