我们已经在FragmentA和FragmentB之间实现了共享元素转换。在FragmentA上,我们有一个RecyclerView,我们在其中监听单击事件并导航到FragmentB。 RecyclerView可以正常工作,但我们无法解决SharedElementTransition的问题。我们已经在此问题上浪费了超过3天的时间。
SharedElementTransition仅在第一个RecyclerView项上正确设置动画(请参见下面的动画),但是当我单击下面的任何其他项时,动画从第一个项目开始(这是错误的并且看起来很奇怪),并且永远不会显示退出动画。
怎么了?
我们为每个recyclerview项上的每个视图设置唯一的transitionName,通过view.tag将其传递给FragmentB(SingleReceiptFragment),然后在FragmentB上,将transitionName设置为Fragment的B视图。
RecyclerView适配器:
class ReceiptsAdapter(private val receiptList : List<Receipt>) : RecyclerView.Adapter<ReceiptsAdapter.ViewHolder>(){
private val dateFormat = SimpleDateFormat("dd/MM/yyyy",Locale.getDefault())
private var onClickListener : View.OnClickListener? = null
inner class ViewHolder(val receiptView : View) : RecyclerView.ViewHolder(receiptView),View.OnCreateContextMenuListener{
init{
receiptView.setOnCreateContextMenuListener(this)
}
override fun onCreateContextMenu(menu: ContextMenu?, p1: View?, p2: ContextMenu.ContextMenuInfo?
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
menu!!.setGroupDividerEnabled(true)
}
menu!!.add(1, R.id.addWarranty, adapterPosition, "Preview")
menu.add(1, R.id.shareReceipt, adapterPosition, "Share")
menu.add(2, R.id.deleteReceipt, adapterPosition, "Remove")
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val receipt = LayoutInflater.from(parent.context).inflate(R.layout.single_receipt_view,parent,false)
receipt.setOnClickListener(onClickListener)
return ViewHolder(receipt)
}
override fun getItemCount(): Int = receiptList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder.receiptView){
store_name.transitionName = "storeName$position"
receipt_date.transitionName = "receiptDate$position"
payment_type.transitionName = "paymentType$position"
amount_of_money.transitionName = "amountOfMoney$position"
arrowIMG.transitionName = "arrowIMG$position"
store_color.transitionName ="storeColor$position"
}
with(holder.itemView){
val bundle = Bundle()
bundle.putParcelable("receipt",receiptList[position])
bundle.putInt("transitionPosition",position)
tag = bundle
store_name.text = receiptList[position].storeName
receipt_date.text = dateFormat.format(Date(receiptList[position].timeAndDate))
payment_type.text = receiptList[position].paymentType
amount_of_money.text = BigDecimal(receiptList[position].amountWithVAT).setScale(2, RoundingMode.HALF_EVEN).toString()
}
MainActivity.storeColor[receiptList[position].storeName]?.let { color->
holder.receiptView.store_color.setBackgroundResource(color)
}
}
fun setOnClickListener(listener : View.OnClickListener){
onClickListener = listener
}
}
我们的FragmentA:
class HomeFragment : Fragment(R.layout.fragment_home), View.OnClickListener {
private var currentActivity : FragmentClick? = null
private val fireStoreCalls : FirestoreCalls by inject()
private val mainActivityVM : MainActivityViewModel by sharedViewModel()
private var receiptAdapter : ReceiptsAdapter? =null
private lateinit var registration : ListenerRegistration
private var receiptList : MutableList<Receipt>? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
latestReceiptsAdapter.setHasFixedSize(true)
latestReceiptsAdapter.layoutManager = LinearLayoutManager(context)
postponeEnterTransition()
latestReceiptsAdapter.doOnPreDraw {
startPostponedEnterTransition()
}
if(isAdded){
if(receiptList== null){
registration = fireStoreCalls.getLatestReceipts(mainActivityVM.firebaseAuth.currentUser!!.uid){
if(receiptList == null){
receiptList = it.toMutableList()
receiptAdapter = ReceiptsAdapter(it)
receiptAdapter?.setOnClickListener(this)
latestReceiptsAdapter.adapter = receiptAdapter
}
else{
receiptList?.clear()
receiptList?.addAll(it)
receiptAdapter?.notifyDataSetChanged()
}
}
}else{
receiptAdapter = ReceiptsAdapter(receiptList!!)
receiptAdapter?.setOnClickListener(this)
latestReceiptsAdapter.adapter=receiptAdapter
}
}
}
override fun onContextItemSelected(item: MenuItem): Boolean {
return when (item.itemId){
R.id.addWarranty -> {
Toast.makeText(context, "OpenReceipt on position ${item.order}", Toast.LENGTH_SHORT).show()
true
}
R.id.shareReceipt -> {
Toast.makeText(context, "shareReceipt on position ${item.order}", Toast.LENGTH_SHORT).show()
true
}
R.id.deleteReceipt -> {
fireStoreCalls.deleteUsersReceipt(mainActivityVM.firebaseAuth.currentUser!!,receiptList!![item.order]){
}
Toast.makeText(context, "DeleteReceipt on position ${item.order}", Toast.LENGTH_SHORT).show()
true
}
else -> super.onContextItemSelected(item)
}
}
override fun onDestroyView() {
super.onDestroyView()
receiptAdapter = null
latestReceiptsAdapter.adapter = null
registration.remove()
}
override fun onDetach() {
super.onDetach()
currentActivity = null
}
override fun onAttach(context: Context) {
super.onAttach(context)
currentActivity = context as? FragmentClick ?: throw IllegalArgumentException("Activity does not implement FragmentClick")
}
override fun onClick(v: View?) {
val singleReceiptFragment = SingleReceiptFragment()
val moveTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
singleReceiptFragment.sharedElementEnterTransition = moveTransition
singleReceiptFragment.enterTransition = AutoTransition()
sharedElementReturnTransition = moveTransition
exitTransition = AutoTransition()
val receivedBundle = v?.tag as? Bundle
singleReceiptFragment.arguments = receivedBundle
val transitionPosition = receivedBundle?.getInt("transitionPosition")
activity?.supportFragmentManager?.beginTransaction()
//.setCustomAnimations(R.anim.fade_in,R.anim.fade_out)
?.addSharedElement(store_name, "storeName$transitionPosition")
?.addSharedElement(receipt_date,"receiptDate$transitionPosition")
?.addSharedElement(payment_type, "paymentType$transitionPosition")
?.addSharedElement(amount_of_money, "amountOfMoney$transitionPosition")
?.addSharedElement(arrowIMG, "arrowIMG$transitionPosition")
?.addSharedElement(store_color, "storeColor$transitionPosition")
?.setReorderingAllowed(true)
?.replace(R.id.mainFragment, singleReceiptFragment)
?.addToBackStack(null)
?.commit()
}
}
还有我们的FragmentB:
class SingleReceiptFragment : Fragment(){
private var itemAdapter : ItemAdapter? = null
private var btnVisibility = View.VISIBLE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
postponeEnterTransition()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val singleReceiptFragmentDataBinding = DetailedReceiptViewBinding.inflate(layoutInflater)
singleReceiptFragmentDataBinding.lifecycleOwner = this
val receipt = arguments?.getParcelable<Receipt>("receipt")
with(singleReceiptFragmentDataBinding){
val transitionPosition = arguments?.getInt("transitionPosition")
root.store_name.transitionName = "storeName$transitionPosition"
root.receipt_date.transitionName = "receiptDate$transitionPosition"
root.payment_type.transitionName = "paymentType$transitionPosition"
root.amount_of_money.transitionName = "amountOfMoney$transitionPosition"
root.arrowIMG.transitionName ="arrowIMG$transitionPosition"
root.store_color.transitionName="storeColor$transitionPosition"
singleReceipt = receipt
registerForContextMenu(billView)
}
exitTransition = TransitionInflater.from(context).inflateTransition(android.R.transition.move)
MainActivity.storeColor[receipt?.storeName]?.let {
receipt?.storeColor = it
singleReceiptFragmentDataBinding.detailedStoreColor.setBackgroundResource(it)
}
receipt?.itemList?.let {
itemAdapter = ItemAdapter(it)
with(singleReceiptFragmentDataBinding.root) {
itemView.layoutManager = LinearLayoutManager(context)
itemView.setHasFixedSize(true)
itemView.adapter = itemAdapter
}
}
singleReceiptFragmentDataBinding.expandBtn.setOnClickListener{
detailedReceipt(btnVisibility)
}
singleReceiptFragmentDataBinding.singleReceipt?.amountWithoutVAT = singleReceiptFragmentDataBinding.singleReceipt?.amountWithoutVAT?.let { BigDecimal(it).setScale(8, RoundingMode.HALF_EVEN).toDouble() }!!
return singleReceiptFragmentDataBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
startPostponedEnterTransition()
}
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
super.onCreateContextMenu(menu, v, menuInfo)
val inflater = MenuInflater(activity)
inflater.inflate(R.menu.long_click_receipt, menu)
}
override fun onContextItemSelected(item: MenuItem): Boolean {
return when (item.itemId){
R.id.addWarranty -> {
Toast.makeText(context, "addWarranty", Toast.LENGTH_SHORT).show()
true
}
R.id.shareReceipt -> {
Toast.makeText(context, "shareReceipt", Toast.LENGTH_SHORT).show()
true
}
R.id.deleteReceipt -> {
Toast.makeText(context, "DeleteReceipt", Toast.LENGTH_SHORT).show()
true
}
else -> super.onContextItemSelected(item)
}
}
override fun onDestroyView() {
super.onDestroyView()
itemView.adapter = null
itemAdapter = null
unregisterForContextMenu(bill_view)
}
}