Demo-RecyclerViewEnterAnimation icon indicating copy to clipboard operation
Demo-RecyclerViewEnterAnimation copied to clipboard

Grid animation is not working with data binding

Open dtunctuncer opened this issue 6 years ago • 4 comments

You can watch this video Here is my code and animation resources are the exactly same as yours

 override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val binding = DataBindingUtil.inflate<FragmentMovieListBinding>(inflater, R.layout.fragment_movie_list, container, false)
        initRecyclerView(binding)
        val model = ViewModelProviders.of(this).get(MovieListViewModel::class.java)
        model.listType = listType
        binding.viewModel = model
        getMovieList(binding)
        return binding.root
    }

    private fun getMovieList(binding: FragmentMovieListBinding) {
        binding.viewModel.getMovieList()
                .subscribe({ movieResponse ->
                    movieResponse.results.let {
                        adapter.setMovieList(it)
                        val animation = AnimationUtils.loadLayoutAnimation(activity, R.anim.grid_layout_animation_from_bottom)
                        binding.listRecyclerView.layoutAnimation = animation
                        binding.listRecyclerView.adapter.notifyDataSetChanged()
                        binding.listRecyclerView.scheduleLayoutAnimation()
                    }

                }, { throwable ->
                    Timber.e(throwable)
                })
    }

    private fun initRecyclerView(binding: FragmentMovieListBinding) {
        val manager = GridLayoutManager(activity, 3)
        binding.listRecyclerView.layoutManager = manager
        binding.listRecyclerView.adapter = adapter
    }

class AdvancedRecyclerView : RecyclerView {

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)

    override fun attachLayoutAnimationParameters(child: View, params: ViewGroup.LayoutParams,
                                                 index: Int, count: Int) {
        val layoutManager = layoutManager
        if (adapter != null && layoutManager is GridLayoutManager) {

            var animationParams: GridLayoutAnimationController.AnimationParameters? = null

            if (params.layoutAnimationParameters == null) {
                // If there are no animation parameters, create new once and attach them to
                // the LayoutParams.
                animationParams = GridLayoutAnimationController.AnimationParameters()
                params.layoutAnimationParameters = animationParams
            }

            // Next we are updating the parameters

            // Set the number of items in the RecyclerView and the index of this item
            animationParams?.count = count
            animationParams?.index = index

            // Calculate the number of columns and rows in the grid
            val columns = layoutManager.spanCount
            animationParams?.columnsCount = columns
            animationParams?.rowsCount = count / columns

            // Calculate the column/row position in the grid
            val invertedIndex = count - 1 - index
            animationParams?.column = columns - 1 - invertedIndex % columns
            animationParams?.row = animationParams!!.rowsCount - 1 - invertedIndex / columns

        } else {
            // Proceed as normal if using another type of LayoutManager
            super.attachLayoutAnimationParameters(child, params, index, count)
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="viewModel"
            type="com.dtunctuncer.todomovielist.ui.discover.movielist.MovieListViewModel" />
    </data>

    <com.dtunctuncer.todomovielist.core.widgets.AdvancedRecyclerView
        android:id="@+id/listRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layoutAnimation="@anim/grid_layout_animation_from_bottom" />
</layout>

dtunctuncer avatar Aug 02 '17 06:08 dtunctuncer

The one time I ran into something similar it was due to me setting the item view visibility to GONE instead of INVISIBLE at the start, causing the item to not being measured properly and the animation to fail. Perhaps you have some similar scenario in onBindViewHolder in the adapter?

patrick-elmquist avatar Aug 02 '17 07:08 patrick-elmquist

Sorry I do not change any visibility in my code.

class MovieListAdapter(val application: Application) : RecyclerView.Adapter<MovieListAdapter.ViewHolder>() {

    private var movieList: List<Movie?>? = null

    init {
        movieList = emptyList()
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.binding.viewModel.setMovie(movieList?.get(position))
    }

    override fun getItemCount(): Int = movieList?.size ?: 0

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = DataBindingUtil.inflate<ItemMovieListBinding>(LayoutInflater.from(parent.context), R.layout.item_movie_list, parent, false)
        val viewModel = MovieListAdapterViewModel(application)
        binding.viewModel = viewModel
        return ViewHolder(binding)
    }

    fun setMovieList(movieList: List<Movie?>?) {
        this.movieList = movieList
        notifyDataSetChanged()
    }

    class ViewHolder(val binding: ItemMovieListBinding) : RecyclerView.ViewHolder(binding.root)
}

class MovieListAdapterViewModel(val app: Application) : AndroidViewModel(app) {

    var movie: ObservableField<Movie> = ObservableField()
    var picture: ObservableField<Drawable> = ObservableField()
    var statusPicture: ObservableField<Drawable> = ObservableField()
    private var bindableFieldTarget: BindableFieldTarget? = null

    fun setMovie(movie: Movie?) {
        bindableFieldTarget = BindableFieldTarget(picture, app.resources, statusPicture)
        Picasso.with(app).load(BuildConfig.SMALL_IMAGE_URL + movie?.posterPath).placeholder(R.drawable.animation_progress).error(R.drawable.error).into(bindableFieldTarget)
        this.movie.set(movie)
    }

    fun onClick() {
        val intent = Intent(app, MovieActivity::class.java)
        intent.putExtra(MovieActivity.ARG_MOVIE, movie.get())
        app.startActivity(intent)
    }
}

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="viewModel"
            type="com.dtunctuncer.todomovielist.ui.discover.movielist.MovieListAdapterViewModel" />
    </data>

    <com.dtunctuncer.todomovielist.core.widgets.RectangleLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="2dp"
        android:onClick="@{() -> viewModel.onClick()}">

        <ImageView
            android:layout_width="36dp"
            android:layout_height="36dp"
            android:layout_gravity="center"
            android:src="@{viewModel.statusPicture}" />


        <ImageView
            android:id="@+id/posterImage"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@{viewModel.picture}"
            android:transitionName="@string/poster_image_trasition_name" />
    </com.dtunctuncer.todomovielist.core.widgets.RectangleLayout>


</layout>

dtunctuncer avatar Aug 02 '17 10:08 dtunctuncer

Is the issue just when using Grids? What happens if you switch to a LinearLayoutManager and the regular RecyclerView?

I've never used the Data Binding apis so not sure how/if they might have an effect on the LayoutAnimation.

patrick-elmquist avatar Aug 02 '17 10:08 patrick-elmquist

Sorry for late answer no I haven't tryed it with LinearLayoutManager I think problem is Data Binding

dtunctuncer avatar Sep 12 '17 07:09 dtunctuncer