利用 RecyclerView 实现垂直交错的网格

来源:互联网 发布:java foreach能倒序 编辑:程序博客网 时间:2024/05/17 21:52

效果如下(关于 RecyclerView 见前文):


MainActivity.java :

package com.crazy.simplerecyclerviewof;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.Menu;import android.view.MenuItem;import android.widget.Toast;public class MainActivity extends AppCompatActivity implements SimpleItemAdapter.OnItemClickListener{    private RecyclerView mRecyclerView;    private SimpleItemAdapter mAdapter;    /* 布局管理器 */    private GridLayoutManager mVerticalGridManager;    /* 修饰 */    private ConnectorDecoration mConnectors;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mRecyclerView = new RecyclerView(this);        mVerticalGridManager = new GridLayoutManager(this, 2,                LinearLayoutManager.VERTICAL, false);        // 垂直网格的连接线修饰        mConnectors = new ConnectorDecoration(this);        // 交错垂直网格        mVerticalGridManager.setSpanSizeLookup(new GridStaggerLookup());        mAdapter = new SimpleItemAdapter(this);        mAdapter.setOnItemClickListener(this);        mRecyclerView.setAdapter(mAdapter);        // 对所有连接应用边缘修饰        mRecyclerView.addItemDecoration(new InsetDecoration(this));        // 默认为垂直布局        selectLayoutManager(R.id.action_grid_vertical);        setContentView(mRecyclerView);    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        getMenuInflater().inflate(R.menu.layout_options, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        return selectLayoutManager(item.getItemId());    }    private boolean selectLayoutManager(int id) {        switch (id){            case R.id.action_grid_vertical:                mRecyclerView.setLayoutManager(mVerticalGridManager);                mRecyclerView.addItemDecoration(mConnectors);                return true;            case R.id.action_add_item:                // 插入新的项                mAdapter.insertItemAtIndex("百家姓:", 1);                return true;            case R.id.action_remove_item:                // 删除第一项                mAdapter.removeItemAtIndex(1);                return true;            default:                return false;        }    }    @Override    public void onItemClick(SimpleItemAdapter.ItemHolder item, int position) {        Toast.makeText(this, item.getSummary(), Toast.LENGTH_SHORT).show();    }}


需要让适配器将数据与视图关联起来:

SimpleItemAdapter.java :

package com.crazy.simplerecyclerviewof;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.ArrayList;import java.util.Arrays;import java.util.List;public class SimpleItemAdapter extends RecyclerView.Adapter<SimpleItemAdapter.ItemHolder> {    /**     * 单击处理程序的接口,与 AdapterView 不同,     * RecyclerView 没有自己的内部接口     */    public interface OnItemClickListener {        public void onItemClick(ItemHolder item, int position);    }    private static final String[] ITEMS = {            "赵...", "钱...", "孙...", "李...",            "周...", "吴...", "郑...", "王...",            "冯...", "陈...", "楮...", "卫..."    };    private List<String> mItems;    private OnItemClickListener mOnItemClickListener;    private LayoutInflater mLayoutInflater;    public SimpleItemAdapter(Context context) {        mLayoutInflater = LayoutInflater.from(context);        // 创建虚拟项的静态列表        mItems = new ArrayList<>();        mItems.addAll(Arrays.asList(ITEMS));        mItems.addAll(Arrays.asList(ITEMS));    }    /**     *  创建     */    @Override    public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View itemView = mLayoutInflater.inflate(R.layout.collection_item, parent, false);        // 创建新的视图        return new ItemHolder(itemView, this);    }    /**     *  绑定     */    @Override    public void onBindViewHolder(ItemHolder holder, int position) {        // 把 position 位置处的数据附加到新的视图        holder.setTitle("Item #" + (position + 1));        holder.setSummary(mItems.get(position));    }    @Override    public int getItemCount() {        return mItems.size();    }    public OnItemClickListener getOnItemClickListener() {        return mOnItemClickListener;    }    public void setOnItemClickListener(OnItemClickListener listener) {        mOnItemClickListener = listener;    }    /* 管理数据集修改的方法 */    public void insertItemAtIndex(String item, int position) {        mItems.add(position, item);        // 通知视图触发变化动画        notifyItemInserted(position);    }    public void removeItemAtIndex(int position) {        if (position >= mItems.size())            return;        mItems.remove(position);        // 通知视图触发变化动画        notifyItemRemoved(position);    }    /**     *  用作与子项关联的元数据(例如当前位置和稳定的 ID)的存储位置,     *  具体的实现通常还提供对视图内部字段的直接访问,从而尽量减少对 findViewById() 的重复调用     */    public static class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener{        private SimpleItemAdapter mParent;        private TextView mTitleView, mSummaryView;        public ItemHolder(View itemView, SimpleItemAdapter parent) {            super(itemView);            itemView.setOnClickListener(this);            mParent = parent;            mTitleView = (TextView)itemView.findViewById(R.id.text_title);            mSummaryView = (TextView)itemView.findViewById(R.id.text_summary);        }        public void setTitle(CharSequence title) {            mTitleView.setText(title);        }        public void setSummary(CharSequence summary) {            mSummaryView.setText(summary);        }        public CharSequence getSummary() {            return mSummaryView.getText();        }        @Override        public void onClick(View v) {            // ViewHolder 处理子视图上的单击事件,并将其发送回在适配器上定义的公共监听接口            // 这样 ViewHolder 就可以在最后的监听器回调中添加位置数据            final OnItemClickListener listener = mParent.getOnItemClickListener();            if (listener != null) {                listener.onItemClick(this, getPosition());            }        }    }}


交错网格,继承 SpanSizeLookup:
GridStaggerLookup.java :
package com.crazy.simplerecyclerviewof;import android.support.v7.widget.GridLayoutManager;/** * 该类用于生成交错效果,要么 1 行 2 列,要么 1 行 1 列 */public class GridStaggerLookup extends GridLayoutManager.SpanSizeLookup {    @Override    public int getSpanSize(int position) {        // 每隔 3 个位置占据 2 列,其他位置则占 1 列        int pos = position % 3 == 0 ? 2 : 1;        return pos;    }}

设置页边距:

InsetDecoration.java :

package com.crazy.simplerecyclerviewof;import android.content.Context;import android.graphics.Rect;import android.support.v7.widget.RecyclerView;import android.view.View;/** * 为每个子项提供页边距 */public class InsetDecoration extends RecyclerView.ItemDecoration {    private int mInsetMargin;    public InsetDecoration (Context context) {        super();        mInsetMargin = context.getResources().getDimensionPixelOffset(R.dimen.inset_margin);    }    @Override    public void getItemOffsets(Rect outRect, View view,                               RecyclerView parent, RecyclerView.State state) {        super.getItemOffsets(outRect, view, parent, state);        // 对子视图的所有 4 个边界应用计算得出的页边距        outRect.set(mInsetMargin, mInsetMargin, mInsetMargin, mInsetMargin);    }}


连接线 ItemDecoration :
ConnectorDecoration.java :
package com.crazy.simplerecyclerviewof;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.support.v7.widget.RecyclerView;import android.support.v7.widget.RecyclerView.ItemDecoration;import android.view.View;/** *  在主要和次要网格项之间绘制连接线 */public class ConnectorDecoration extends ItemDecoration {    private Paint mLinePaint;    private int mLineLength;    public ConnectorDecoration(Context context) {        super();        mLineLength =context.getResources()                .getDimensionPixelOffset(R.dimen.inset_margin);        int connectorStroke = context.getResources()                .getDimensionPixelOffset(R.dimen.connector_stroke);        // 允许锯齿        mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mLinePaint.setColor(Color.RED);        mLinePaint.setStyle(Paint.Style.STROKE);        mLinePaint.setStrokeWidth(connectorStroke);    }    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        final RecyclerView.LayoutManager manager = parent.getLayoutManager();        // 遍历子视图,并在未占据两列的每个子项上绘制中心线        for (int i = 0; i < parent.getChildCount(); i++) {            final View child = parent.getChildAt(i);            boolean isLarge = parent                    .getChildViewHolder(child)                    .getPosition() % 3 == 0;            // 得到视图当前所在的位置,以此绘制线段            if (!isLarge) {                final int childLeft = manager.getDecoratedLeft(child);                final int childRight = manager.getDecoratedRight(child);                final int childTop = manager.getDecoratedTop(child);                final int x = childLeft + ((childRight - childLeft) / 2);                c.drawLine(x, childTop - mLineLength,                        x, childTop + mLineLength,                        mLinePaint);            }        }    }}


collection_item.xml :

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:padding="8dp"    android:background="#CCF"    android:layout_width="match_parent"    android:layout_height="wrap_content">    <TextView        android:id="@+id/text_title"        android:textAppearance="?android:textAppearanceLarge"        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <TextView        android:id="@+id/text_summary"        android:textAppearance="?android:textAppearanceMedium"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></LinearLayout>



dimens.xml :

<resources>    <!-- Default screen margins, per the Android Design guidelines. -->    <dimen name="activity_horizontal_margin">16dp</dimen>    <dimen name="activity_vertical_margin">16dp</dimen>    <dimen name="fab_margin">16dp</dimen>    <dimen name="inset_margin">8dp</dimen>    <dimen name="connector_stroke">2dp</dimen></resources>



layout_options.xml :


<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    tools:context="com.crazy.extendibleview.MainActivity">    <!--app:showAsAction="ifRoom"        如果有位置才显示,不然就出现在右边的三个点中-->    <item        android:id="@+id/action_add_item"        android:title="Add Item"        android:icon="@android:drawable/ic_menu_add"        app:showAsAction="ifRoom" />    <item        android:id="@+id/action_remove_item"        android:title="Remove Item"        android:icon="@android:drawable/ic_menu_delete"        android:showAsAction="ifRoom" />    <!--app:showAsAction="ifRoom"        不显示在界面上,只让出现在右边的三个点中-->    <item        android:id="@+id/action_grid_vertical"        android:title="Vertical Grid"        android:showAsAction="never" /></menu>



0 0