您的位置:首页 > 其它

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

2015-12-06 23:37 441 查看
效果如下(关于 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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: