com.alexive.graphicalutils.fragments.RecyclerViewFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.alexive.graphicalutils.fragments.RecyclerViewFragment.java

Source

/*
 * Copyright (C) 2016 J. Oliveira
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alexive.graphicalutils.fragments;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.alexive.graphicalutils.R;
import com.alexive.graphicalutils.lists.ListAdapter;
import com.alexive.graphicalutils.lists.OnItemClickListener;
import com.alexive.graphicalutils.lists.OnItemLongClickListener;
import com.alexive.graphicalutils.view.ViewUtils;

/**
 * Simple fragment containing a RecyclerView. Has support for an empty view (even if the chosen
 * adapter is not a subclass of this library's ListAdapter class) and click and long click
 * listeners. Still, it'll work best if you use a class derived from {@link ListAdapter}.
 *
 * Just override {@link #onViewCreated(View, Bundle)} (don't forget to call super!) and you can go
 * from there
 */
public class RecyclerViewFragment extends Fragment {

    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter adapter;
    private OnItemClickListener mClickListener;
    private OnItemLongClickListener mOnItemLongClickListener;
    private Listener mOnItemTouchListener;
    private String emptyText;
    private View emptyView;
    private boolean emptyViewAddedToLayout = false;
    private boolean isEmptyViewEmptyText;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.recycler_fragment_layout, container, false);
        mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
        if (this.adapter != null)
            setAdapter(adapter);
        if (this.emptyText != null)
            setEmptyText(emptyText);
        else if (this.emptyView != null && !isEmptyViewEmptyText)
            if (emptyViewAddedToLayout)
                actuallySetEmptyView();
            else
                setEmptyView(emptyView);

        return view;
    }

    /**
     * @return The fragment's recyclerView
     */
    public RecyclerView getRecyclerView() {
        return mRecyclerView;
    }

    /**
     * Gets the RecyclerView's adapter.
     *
     * @return The adapter provided when you called setAdapter, or null if the recyclerView as no
     * adapter.
     */
    public RecyclerView.Adapter getAdapter() {
        return adapter != null ? adapter : mRecyclerView != null ? mRecyclerView.getAdapter() : null;
    }

    /**
     * Sets the adapter to the recyclerView
     */
    public void setAdapter(RecyclerView.Adapter adapter) {
        this.adapter = adapter;
        if (this.mRecyclerView == null)
            return;
        mRecyclerView.setAdapter(adapter);
        if (mOnItemTouchListener != null)
            mRecyclerView.removeOnItemTouchListener(mOnItemTouchListener);
        else
            mOnItemTouchListener = new Listener();
        if (adapter instanceof ListAdapter) {
            if (mClickListener != null)
                ((ListAdapter) adapter).setOnItemClickListener(mClickListener);
            if (mOnItemLongClickListener != null)
                ((ListAdapter) adapter).setOnItemLongClickListener(mOnItemLongClickListener);
        } else
            mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);
        if (emptyViewAddedToLayout && emptyView != null)
            actuallySetEmptyView();
    }

    /**
     * Sets the callback to be called when the user clicks an item.
     */
    public void setOnItemClickListener(OnItemClickListener listener) {
        mClickListener = listener;
        if (adapter != null && adapter instanceof ListAdapter)
            ((ListAdapter) adapter).setOnItemClickListener(mClickListener);
    }

    /**
     * Sets the callback to be called when the user long clicks an item.
     */
    public void setOnItemLongClickListener(OnItemLongClickListener listener) {
        mOnItemLongClickListener = listener;
        if (adapter != null && adapter instanceof ListAdapter)
            ((ListAdapter) adapter).setOnItemLongClickListener(mOnItemLongClickListener);
    }

    /**
     * Notifies a change in the data set.
     */
    public void notifyDataSetChanged() {
        if (adapter != null)
            adapter.notifyDataSetChanged();
    }

    /**
     * Sets a message to be displayed when the list is empty.
     *
     * @param emptyText Will be shown when the list is empty.
     */
    public void setEmptyText(String emptyText) {
        this.emptyText = emptyText;
        View view = getView();
        if (view == null)
            return;
        TextView textView = (TextView) view.findViewById(android.R.id.text1);
        textView.setText(emptyText);

        this.emptyView = textView;
        actuallySetEmptyView();
        isEmptyViewEmptyText = true;

    }

    /**
     * Sets a view to be displayed when the list is empty. This is the same as {@link
     * RecyclerViewFragment#setEmptyView(View, FrameLayout.LayoutParams)} passing null has the
     * second parameter. The view will be centered and will not stretch to the screen's width.
     * @param view Displayed when the list is empty.
     */
    public void setEmptyView(View view) {
        setEmptyView(view, null);
    }

    /**
     * Sets a view to be displayed when the list is empty with optional LayoutParams.
     * @param view Displayed when the list is empty.
     * @param params Information about how view's layout in the countainer.
     */
    public void setEmptyView(View view, FrameLayout.LayoutParams params) {
        emptyView = view;
        isEmptyViewEmptyText = true;
        FrameLayout frameLayout = (FrameLayout) getView();
        if (frameLayout == null)
            return;
        //In order to avoid having more than one emptyViews added to the layout
        if (frameLayout.getChildCount() > 2)
            frameLayout.removeViewAt(2);
        if (this.emptyText != null)
            frameLayout.findViewById(android.R.id.text1).setVisibility(View.GONE);
        if (params == null) {
            params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
            params.gravity = Gravity.CENTER;
        }

        frameLayout.addView(view, 1, params);
        this.emptyViewAddedToLayout = true;
        actuallySetEmptyView();
    }

    private void actuallySetEmptyView() {
        if (getAdapter() != null)
            if (getAdapter() instanceof ListAdapter)
                ((ListAdapter) getAdapter()).setEmptyView(emptyView);
            else {
                ListAdapter.DataSetObserver observer = new ListAdapter.DataSetObserver() {
                    @Override
                    public void handleDataSizeChanged() {
                        if (emptyView == null)
                            return;
                        if (getAdapter().getItemCount() == 0) {
                            if (emptyView.getVisibility() != View.VISIBLE) {
                                emptyView.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        int width = getView().getWidth();
                                        int height = getView().getHeight();
                                        ViewUtils.createCircularReveal(emptyView, width / 2, height / 2,
                                                Math.max(width, height));
                                    }
                                });
                            }
                        } else {
                            if (emptyView.getVisibility() == View.VISIBLE) {
                                emptyView.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        int width = getView().getWidth();
                                        int height = getView().getHeight();
                                        ViewUtils.createCircularRevealInverse(emptyView, width / 2, height / 2,
                                                width, true);
                                    }
                                });
                            }
                        }
                    }
                };
                getAdapter().registerAdapterDataObserver(observer);
                if (getAdapter().getItemCount() != 0)
                    this.emptyView.setVisibility(View.GONE);
            }
    }

    private class Listener implements RecyclerView.OnItemTouchListener {

        private GestureDetector mGestureDetector;

        public Listener() {
            mGestureDetector = new GestureDetector(mRecyclerView.getContext(),
                    new GestureDetector.SimpleOnGestureListener() {

                        @Override
                        public boolean onSingleTapUp(MotionEvent e) {
                            return true;
                        }

                        @Override
                        public void onLongPress(MotionEvent e) {
                            View child = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
                            if (child != null)
                                if (mOnItemLongClickListener != null)
                                    mOnItemLongClickListener.onItemLongClick(child,
                                            mRecyclerView.getChildAdapterPosition(child));

                        }
                    });
        }

        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
            View child = rv.findChildViewUnder(e.getX(), e.getY());
            if (child != null && !mGestureDetector.onTouchEvent(e)) {
                if (mClickListener != null)
                    mClickListener.onItemClicked(child, mRecyclerView.getChildAdapterPosition(child));
            }
            return true;
        }

        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e) {

        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

        }
    }
}