赞
踩
- package com.zw.flowlayoutdemo;
-
- import android.graphics.Rect;
- import android.support.v7.widget.RecyclerView;
- import android.util.Log;
- import android.util.SparseArray;
- import android.view.View;
- import android.view.ViewGroup;
-
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * @Description:流失布局
- */
- public class FlowLayoutManager extends RecyclerView.LayoutManager {
-
- private static final String TAG = FlowLayoutManager.class.getSimpleName();
- final FlowLayoutManager self = this;
-
- protected int width, height;
- private int left, top, right;
- //最大容器的宽度
- private int usedMaxWidth;
- //竖直方向上的偏移量
- private int verticalScrollOffset = 0;
-
- public int getTotalHeight() {
- return totalHeight;
- }
-
- //计算显示的内容的高度
- protected int totalHeight = 0;
- private Row row = new Row();
- private List<Row> lineRows = new ArrayList<>();
-
- //保存所有的Item的上下左右的偏移量信息
- private SparseArray<Rect> allItemFrames = new SparseArray<>();
-
- public FlowLayoutManager() {
- //设置主动测量规则,适应recyclerView高度为wrap_content
- setAutoMeasureEnabled(true);
- }
-
- //每个item的定义
- public class Item {
- int useHeight;
- View view;
-
- public void setRect(Rect rect) {
- this.rect = rect;
- }
-
- Rect rect;
-
- public Item(int useHeight, View view, Rect rect) {
- this.useHeight = useHeight;
- this.view = view;
- this.rect = rect;
- }
- }
-
- //行信息的定义
- public class Row {
- public void setCuTop(float cuTop) {
- this.cuTop = cuTop;
- }
-
- public void setMaxHeight(float maxHeight) {
- this.maxHeight = maxHeight;
- }
-
- //每一行的头部坐标
- float cuTop;
- //每一行需要占据的最大高度
- float maxHeight;
- //每一行存储的item
- List<Item> views = new ArrayList<>();
- public void addViews(Item view) {
- views.add(view);
- }
- }
-
- @Override
- public RecyclerView.LayoutParams generateDefaultLayoutParams() {
- return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- }
-
- //该方法主要用来获取每一个item在屏幕上占据的位置
- @Override
- public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
- Log.d(TAG, "onLayoutChildren");
- totalHeight = 0;
- int cuLineTop = top;
- //当前行使用的宽度
- int cuLineWidth = 0;
- int itemLeft;
- int itemTop;
- int maxHeightItem = 0;
- row = new Row();
- lineRows.clear();
- allItemFrames.clear();
- removeAllViews();
- if (getItemCount() == 0) {
- detachAndScrapAttachedViews(recycler);
- verticalScrollOffset = 0;
- return;
- }
- if (getChildCount() == 0 && state.isPreLayout()) {
- return;
- }
- //onLayoutChildren方法在RecyclerView 初始化时 会执行两遍
- detachAndScrapAttachedViews(recycler);
- if (getChildCount() == 0) {
- width = getWidth();
- height = getHeight();
- left = getPaddingLeft();
- right = getPaddingRight();
- top = getPaddingTop();
- usedMaxWidth = width - left - right;
- }
-
- for (int i = 0; i < getItemCount(); i++) {
- Log.d(TAG, "index:" + i);
- View childAt = recycler.getViewForPosition(i);
- if (View.GONE == childAt.getVisibility()) {
- continue;
- }
- measureChildWithMargins(childAt, 0, 0);
- int childWidth = getDecoratedMeasuredWidth(childAt);
- int childHeight = getDecoratedMeasuredHeight(childAt);
- int childUseWidth = childWidth;
- int childUseHeight = childHeight;
- //如果加上当前的item还小于最大的宽度的话就增加,否则就换行
- if (cuLineWidth + childUseWidth <= usedMaxWidth) {
- itemLeft = left + cuLineWidth;
- itemTop = cuLineTop;
- Rect frame = allItemFrames.get(i);
- if (frame == null) {
- frame = new Rect();
- }
- frame.set(itemLeft, itemTop, itemLeft + childWidth, itemTop + childHeight);
- allItemFrames.put(i, frame);
- cuLineWidth += childUseWidth;
- maxHeightItem = Math.max(maxHeightItem, childUseHeight);
- row.addViews(new Item(childUseHeight, childAt, frame));
- row.setCuTop(cuLineTop);
- row.setMaxHeight(maxHeightItem);
- } else {
- //换行
- formatAboveRow();
- cuLineTop += maxHeightItem;
- totalHeight += maxHeightItem;
- itemTop = cuLineTop;
- itemLeft = left;
- Rect frame = allItemFrames.get(i);
- if (frame == null) {
- frame = new Rect();
- }
- frame.set(itemLeft, itemTop, itemLeft + childWidth, itemTop + childHeight);
- allItemFrames.put(i, frame);
- cuLineWidth = childUseWidth;
- maxHeightItem = childUseHeight;
- row.addViews(new Item(childUseHeight, childAt, frame));
- row.setCuTop(cuLineTop);
- row.setMaxHeight(maxHeightItem);
- }
- //不要忘了最后一行进行刷新下布局
- if (i == getItemCount() - 1) {
- formatAboveRow();
- totalHeight += maxHeightItem;
- }
-
- }
- totalHeight = Math.max(totalHeight, getVerticalSpace());
- Log.d(TAG, "onLayoutChildren totalHeight:" + totalHeight);
- fillLayout(recycler, state);
- }
-
- //对出现在屏幕上的item进行展示,超出屏幕的item回收到缓存中
- private void fillLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
- if (state.isPreLayout() || getItemCount() == 0) { // 跳过preLayout,preLayout主要用于支持动画
- return;
- }
-
- // 当前scroll offset状态下的显示区域
- Rect displayFrame = new Rect(getPaddingLeft(), getPaddingTop() + verticalScrollOffset,
- getWidth() - getPaddingRight(), verticalScrollOffset + (getHeight() - getPaddingBottom()));
-
- //对所有的行信息进行遍历
- for (int j = 0; j < lineRows.size(); j++) {
- Row row = lineRows.get(j);
- float lineTop = row.cuTop;
- float lineBottom = lineTop + row.maxHeight;
- //如果该行在屏幕中,进行放置item
- // if (lineTop < displayFrame.bottom && displayFrame.top < lineBottom) {
- List<Item> views = row.views;
- for (int i = 0; i < views.size(); i++) {
- View scrap = views.get(i).view;
- measureChildWithMargins(scrap, 0, 0);
- addView(scrap);
- Rect frame = views.get(i).rect;
- //将这个item布局出来
- layoutDecoratedWithMargins(scrap,
- frame.left,
- frame.top - verticalScrollOffset,
- frame.right,
- frame.bottom - verticalScrollOffset);
- }
- // } else {
- // //将不在屏幕中的item放到缓存中
- // List<Item> views = row.views;
- // for (int i = 0; i < views.size(); i++) {
- // View scrap = views.get(i).view;
- // removeAndRecycleView(scrap, recycler);
- // }
- // }
- }
- }
-
- /**
- * 计算每一行没有居中的viewgroup,让居中显示
- */
- private void formatAboveRow() {
- List<Item> views = row.views;
- for (int i = 0; i < views.size(); i++) {
- Item item = views.get(i);
- View view = item.view;
- int position = getPosition(view);
- //如果该item的位置不在该行中间位置的话,进行重新放置
- if (allItemFrames.get(position).top < row.cuTop + (row.maxHeight - views.get(i).useHeight) / 2) {
- Rect frame = allItemFrames.get(position);
- if (frame == null) {
- frame = new Rect();
- }
- frame.set(allItemFrames.get(position).left, (int) (row.cuTop + (row.maxHeight - views.get(i).useHeight) / 2),
- allItemFrames.get(position).right, (int) (row.cuTop + (row.maxHeight - views.get(i).useHeight) / 2 + getDecoratedMeasuredHeight(view)));
- allItemFrames.put(position, frame);
- item.setRect(frame);
- views.set(i, item);
- }
- }
- row.views = views;
- lineRows.add(row);
- row = new Row();
- }
-
- /**
- * 竖直方向需要滑动的条件
- *
- * @return
- */
- @Override
- public boolean canScrollVertically() {
- return true;
- }
-
- //监听竖直方向滑动的偏移量
- @Override
- public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
- RecyclerView.State state) {
-
- Log.d("TAG", "totalHeight:" + totalHeight);
- //实际要滑动的距离
- int travel = dy;
-
- //如果滑动到最顶部
- if (verticalScrollOffset + dy < 0) {//限制滑动到顶部之后,不让继续向上滑动了
- travel = -verticalScrollOffset;//verticalScrollOffset=0
- } else if (verticalScrollOffset + dy > totalHeight - getVerticalSpace()) {//如果滑动到最底部
- travel = totalHeight - getVerticalSpace() - verticalScrollOffset;//verticalScrollOffset=totalHeight - getVerticalSpace()
- }
-
- //将竖直方向的偏移量+travel
- verticalScrollOffset += travel;
-
- // 平移容器内的item
- offsetChildrenVertical(-travel);
- fillLayout(recycler, state);
- return travel;
- }
-
- private int getVerticalSpace() {
- return self.getHeight() - self.getPaddingBottom() - self.getPaddingTop();
- }
-
- public int getHorizontalSpace() {
- return self.getWidth() - self.getPaddingLeft() - self.getPaddingRight();
- }
- }
-
- package com.zw.flowlayoutdemo;
-
- import android.os.Handler;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.support.v7.widget.RecyclerView;
- import android.text.Editable;
- import android.text.TextUtils;
- import android.text.TextWatcher;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.Toast;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import java.util.regex.PatternSyntaxException;
-
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
-
- private RecyclerView mRecyclerView;
- private EditText mEditText;
- private Button mBtnAdd;
-
- private MyAdapter myAdapter;
- private List<String>mList=new ArrayList<>();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initView();
- initData();
- }
-
- private void initData() {
- List<String>list=new ArrayList<>();
- String [] str=new String[]{"我喜欢你","你可以的","我们为什么不换一种方式","我爱你哟","你用了什么东西"};
- for (int i = 0; i <5 ; i++) {
- list.add(str[i]);
- }
- mList.clear();
- mList.addAll(list);
- myAdapter.notifyDataSetChanged();
- }
-
- private void initView() {
- mRecyclerView=findViewById(R.id.rv_main);
- mBtnAdd=findViewById(R.id.btn_add);
- mBtnAdd.setOnClickListener(this);
- mEditText=findViewById(R.id.editText);
- myAdapter=new MyAdapter(this,mList);
- FlowLayoutManager flowLayoutManager=new FlowLayoutManager();
- mRecyclerView.addItemDecoration(new SpaceItemDecoration(10));
- mRecyclerView.setLayoutManager(flowLayoutManager);
- mRecyclerView.setAdapter(myAdapter);
- mEditText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
-
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- checkName(s,mEditText);
- }
- });
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()){
- case R.id.btn_add:
- addItem();
- break;
- }
- }
-
- private void addItem() {
- String txt=mEditText.getText().toString();
- if (txt==null || txt.length()==0 || txt.equals("")) {
- return;
- } else {
- mRecyclerView.setVisibility(View.VISIBLE);
-
- //是否有相同的元素
- if (mList.contains(txt)) {
- Toast.makeText(this, "已存在相同的词", Toast.LENGTH_LONG).show();
- return;
- } else {
- mList.add(txt);
- }
- myAdapter.notifyDataSetChanged();
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- mRecyclerView.scrollToPosition(myAdapter.getItemCount() - 1);
- }
- }, 2000);
- mEditText.setText("");
- }
- }
-
-
- /**
- * 检查输入的名称的合法性
- *
- * @param editable
- * @param editText
- */
- private void checkName(Editable editable, EditText editText) {
- String inputStr = editable.toString().trim();
- String str = stringFilter(inputStr);
- if (!inputStr.equals(str)) {
- editText.setText(str);
- editText.setSelection(editText.getText().toString().length());
- return;
- }
- int length = getTextLength(inputStr);
- if (length > 20) {
- String newStr = getStringWithSubLength(inputStr, 20);
- editText.setText(newStr);
- editText.setSelection(editText.getText().toString().length());
- }
- }
-
- /**
- * 只允许字母、汉字
- * @param str
- * @return
- * @throws PatternSyntaxException
- */
- public String stringFilter(String str) throws PatternSyntaxException {
- // 只允许字母、汉字
- String regEx = "[^a-zA-Z\\u4E00-\\u9FA5]";
- Pattern p = Pattern.compile(regEx);
- Matcher m = p.matcher(str);
- return m.replaceAll("").trim();
- }
-
- /**
- * 获取字符数量 汉字占2个,英文占一个
- *
- * @param text
- * @return
- */
- public int getTextLength(String text) {
- int length = 0;
- for (int i = 0; i < text.length(); i++) {
- if (text.charAt(i) > 255) {
- length += 2;
- } else {
- length++;
- }
- }
- return length;
- }
-
-
- public String getStringWithSubLength(String source, int maxCharLength) {
- if (TextUtils.isEmpty(source)) {
- return "";
- }
- if (getTextLength(source) <= maxCharLength) {
- return source;
- }
- char[] childrens = source.toCharArray();
- for (int i = 0; i < childrens.length; i++) {
- StringBuilder builder = new StringBuilder();
- for (int j = 0; j <= i; j++) {
- builder.append(childrens[j]);
- }
- if (getTextLength(builder.toString()) > maxCharLength) {
- return builder.replace(builder.length() - 1, builder.length(), "").toString();
- }
- }
- return "";
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。