流式布局+recyclerview的簡單使用

如果可以幫助到你,可以給我點(diǎn)個(gè)贊嗎?

接口

 String BASE_URL = "https://www.wanandroid.com/";
/**
     * 獲取體系數(shù)據(jù)
     *
     * @return
     */
    @GET("tree/json")
    Observable<TreeBean> getTree();

1.fragment (根據(jù)自己需求修改成activity)

package wanandroid.two.com.wanandroid.ui.fragment;


import android.content.Intent;
import android.os.Bundle;
import android.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

import butterknife.BindView;
import wanandroid.two.com.wanandroid.R;
import wanandroid.two.com.wanandroid.base.BaseFragment;
import wanandroid.two.com.wanandroid.bean.TreeBean;
import wanandroid.two.com.wanandroid.bean.TreeListBean;
import wanandroid.two.com.wanandroid.mvp.p.TreePre;
import wanandroid.two.com.wanandroid.mvp.v.TreeView;
import wanandroid.two.com.wanandroid.ui.activity.MainActivity;
import wanandroid.two.com.wanandroid.ui.activity.TreeEssayActivity;
import wanandroid.two.com.wanandroid.ui.adapter.MyTreeAdapter;

/**
 * A simple {@link Fragment} subclass.
 */
public class MyTreeFragment extends BaseFragment<TreeView,TreePre> implements TreeView{


    @BindView(R.id.Mrv)
    RecyclerView Mrv;
    private MyTreeAdapter mTreeAdapter;
    private ArrayList<TreeBean.DataBean> mList;



    public MyTreeFragment() {
        // Required empty public constructor
    }

    @Override
    protected TreePre Getpreseter() {
        return new TreePre();
    }

    @Override
    protected int GetId() {
        return R.layout.fragment_my_tree;
    }

    @Override
    protected void initView(View inflate) {
        Mrv.setLayoutManager(new LinearLayoutManager(getActivity()));
        mList = new ArrayList<>();
        mTreeAdapter = new MyTreeAdapter(mList, getActivity());
        Mrv.setAdapter(mTreeAdapter);
        presenter.setTree();

        mTreeAdapter.setOnItemCLick(new MyTreeAdapter.OnItemCLick() {
            @Override
            public void onItemClick(TreeBean.DataBean bean) {
                Intent intent = new Intent(getActivity(), TreeEssayActivity.class);
                intent.putExtra("bean",bean);
                startActivity(intent);
            }
        });
    }

    @Override
    public void getTree(TreeBean treeBean) {
        List<TreeBean.DataBean> data = treeBean.getData();
        mList.clear();
        mList.addAll(data);
        mTreeAdapter.notifyDataSetChanged();
    }

    @Override
    public void getTreeList(TreeListBean tree) {

    }

    @Override
    public void setError(String error) {

    }
}

2.主頁面布局只需一個(gè)recyclerview就行

3.自定義view

package com.example.tolovepy.everywheretrip.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class FlowLayout extends ViewGroup {

   private List<Line> mLines   = new ArrayList<Line>(); // 用來記錄描述有多少行View
   private Line        mCurrrenLine;   // 用來記錄當(dāng)前已經(jīng)添加到了哪一行
   private int         mHorizontalSpace    = 40;
   private int         mVerticalSpace      = mHorizontalSpace;
   private int mMaxLines = -1;

   public int getMaxLines() {
       return mMaxLines;
   }

   public void setMaxLines(int maxLines) {
       mMaxLines = maxLines;
   }

   public FlowLayout(Context context, AttributeSet attrs) {
       super(context, attrs);
   }

   public FlowLayout(Context context) {
       super(context);
   }

   public void setSpace(int horizontalSpace, int verticalSpace) {
       this.mHorizontalSpace = horizontalSpace;
       this.mVerticalSpace = verticalSpace;
   }

   public void clearAll(){
       mLines.clear();
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       // 清空
       mLines.clear();
       mCurrrenLine = null;

       int layoutWidth = MeasureSpec.getSize(widthMeasureSpec);

       // 獲取行最大的寬度
       int maxLineWidth = layoutWidth - getPaddingLeft() - getPaddingRight();

       // 測量孩子
       int count = getChildCount();
       for (int i = 0; i < count; i++)
       {
           View view = getChildAt(i);

           // 如果孩子不可見
           if (view.getVisibility() == View.GONE)
           {
               continue;
           }

           // 測量孩子
           measureChild(view, widthMeasureSpec, heightMeasureSpec);

           // 往lines添加孩子
           if (mCurrrenLine == null)
           {
               // 說明還沒有開始添加孩子
               mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);

               // 添加到 Lines中
               mLines.add(mCurrrenLine);

               // 行中一個(gè)孩子都沒有
               mCurrrenLine.addView(view);
           }
           else
           {
               // 行不為空,行中有孩子了
               boolean canAdd = mCurrrenLine.canAdd(view);
               if (canAdd) {
                   // 可以添加
                   mCurrrenLine.addView(view);
               }
               else {
                   // 不可以添加,裝不下去
                   // 換行
                   if (mMaxLines >0){
                       if (mLines.size()<mMaxLines){
                           // 新建行
                           mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);
                           // 添加到lines中
                           mLines.add(mCurrrenLine);
                           // 將view添加到line
                           mCurrrenLine.addView(view);
                       }
                   }else {
                       // 新建行
                       mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);
                       // 添加到lines中
                       mLines.add(mCurrrenLine);
                       // 將view添加到line
                       mCurrrenLine.addView(view);
                   }
               }
           }
       }

       // 設(shè)置自己的寬度和高度
       int measuredWidth = layoutWidth;
       // paddingTop + paddingBottom + 所有的行間距 + 所有的行的高度

       float allHeight = 0;
       for (int i = 0; i < mLines.size(); i++)
       {
           float mHeigth = mLines.get(i).mHeigth;

           // 加行高
           allHeight += mHeigth;
           // 加間距
           if (i != 0)
           {
               allHeight += mVerticalSpace;
           }
       }

       int measuredHeight = (int) (allHeight + getPaddingTop() + getPaddingBottom() + 0.5f);
       setMeasuredDimension(measuredWidth, measuredHeight);
   }

   @Override
   protected void onLayout(boolean changed, int l, int t, int r, int b)
   {
       // 給Child 布局---> 給Line布局

       int paddingLeft = getPaddingLeft();
       int offsetTop = getPaddingTop();
       for (int i = 0; i < mLines.size(); i++)
       {
           Line line = mLines.get(i);

           // 給行布局
           line.layout(paddingLeft, offsetTop);

           offsetTop += line.mHeigth + mVerticalSpace;
       }
   }

   class Line
   {
       // 屬性
       private List<View>  mViews  = new ArrayList<View>();    // 用來記錄每一行有幾個(gè)View
       private float       mMaxWidth;                          // 行最大的寬度
       private float       mUsedWidth;                     // 已經(jīng)使用了多少寬度
       private float       mHeigth;                            // 行的高度
       private float       mMarginLeft;
       private float       mMarginRight;
       private float       mMarginTop;
       private float       mMarginBottom;
       private float       mHorizontalSpace;                   // View和view之間的水平間距

       // 構(gòu)造
       public Line(int maxWidth, int horizontalSpace) {
           this.mMaxWidth = maxWidth;
           this.mHorizontalSpace = horizontalSpace;
       }

       // 方法
       /**
        * 添加view,記錄屬性的變化
        * 
        * @param view
        */
       public void addView(View view)
       {
           // 加載View的方法

           int size = mViews.size();
           int viewWidth = view.getMeasuredWidth();
           int viewHeight = view.getMeasuredHeight();
           // 計(jì)算寬和高
           if (size == 0)
           {
               // 說還沒有添加View
               if (viewWidth > mMaxWidth)
               {
                   mUsedWidth = mMaxWidth;
               }
               else
               {
                   mUsedWidth = viewWidth;
               }
               mHeigth = viewHeight;
           }
           else
           {
               // 多個(gè)view的情況
               mUsedWidth += viewWidth + mHorizontalSpace;
               mHeigth = mHeigth < viewHeight ? viewHeight : mHeigth;
           }

           // 將View記錄到集合中
           mViews.add(view);
       }

       /**
        * 用來判斷是否可以將View添加到line中
        * 
        * @param view
        * @return
        */
       public boolean canAdd(View view)
       {
           // 判斷是否能添加View

           int size = mViews.size();

           if (size == 0) { return true; }

           int viewWidth = view.getMeasuredWidth();

           // 預(yù)計(jì)使用的寬度
           float planWidth = mUsedWidth + mHorizontalSpace + viewWidth;

           if (planWidth > mMaxWidth)
           {
               // 加不進(jìn)去
               return false;
           }

           return true;
       }

       /**
        * 給孩子布局
        * 
        * @param offsetLeft
        * @param offsetTop
        */
       public void layout(int offsetLeft, int offsetTop)
       {
           // 給孩子布局

           int currentLeft = offsetLeft;

           int size = mViews.size();
           // 判斷已經(jīng)使用的寬度是否小于最大的寬度
           float extra = 0;
           float widthAvg = 0;
           if (mMaxWidth > mUsedWidth)
           {
               extra = mMaxWidth - mUsedWidth;
               widthAvg = extra / size;
           }

           for (int i = 0; i < size; i++)
           {
               View view = mViews.get(i);
               int viewWidth = view.getMeasuredWidth();
               int viewHeight = view.getMeasuredHeight();

               // 判斷是否有富余
               if (widthAvg != 0)
               {
                   // 改變寬度,變?yōu)椴桓淖?避免最后一行因label不足,單個(gè)label變寬
                   //int newWidth = (int) (viewWidth + widthAvg + 0.5f);
                   int newWidth = viewWidth;
                   int widthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
                   int heightMeasureSpec = MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY);
                   view.measure(widthMeasureSpec, heightMeasureSpec);

                   viewWidth = view.getMeasuredWidth();
                   viewHeight = view.getMeasuredHeight();
               }

               // 布局
               int left = currentLeft;
               int top = (int) (offsetTop + (mHeigth - viewHeight) / 2 +
                           0.5f);
               // int top = offsetTop;
               int right = left + viewWidth;
               int bottom = top + viewHeight;
               view.layout(left, top, right, bottom);

               currentLeft += viewWidth + mHorizontalSpace;
           }
       }
   }

}

4.使用recyclerview適配器

package wanandroid.two.com.wanandroid.ui.adapter;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import wanandroid.two.com.wanandroid.R;
import wanandroid.two.com.wanandroid.bean.TreeBean;
import wanandroid.two.com.wanandroid.widget.FlowLayout;

public class MyTreeAdapter extends RecyclerView.Adapter<MyTreeAdapter.ViewHolder> {

    private List<TreeBean.DataBean> mList;
    private Context context;

    public MyTreeAdapter(List<TreeBean.DataBean> list, Context context) {
        mList = list;
        this.context = context;
    }


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View inflate = LayoutInflater.from(context).inflate(R.layout.item_tree, null);
        ViewHolder viewHolder = new ViewHolder(inflate);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        viewHolder.mFl.removeAllViews();
        final TreeBean.DataBean bean = mList.get(i);
        //獲取標(biāo)題
        String name = bean.getName();
        //獲取相關(guān)信息標(biāo)題
        List<TreeBean.DataBean.ChildrenBean> list = bean.getChildren();
        //添加
        viewHolder.mTvTitle.setText(name);
        for (int j = 0; j < list.size(); j++) {
            TextView inflate = (TextView) LayoutInflater.from(context).inflate(R.layout.item_label, null);
            String s = list.get(j).getName();
            inflate.setText(s);
            viewHolder.mFl.addView(inflate);
        }

        viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnItemCLick!=null){
                    mOnItemCLick.onItemClick(bean);
                }
            }
        });

    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.mTv_Title)
        TextView mTvTitle;
        @BindView(R.id.mFl)
        FlowLayout mFl;
        @BindView(R.id.mIv_jump)
        ImageView mIvJump;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }

    private OnItemCLick mOnItemCLick;

    public void setOnItemCLick(OnItemCLick onItemCLick) {
        mOnItemCLick = onItemCLick;
    }

    public interface OnItemCLick{
        void onItemClick(TreeBean.DataBean bean);
    }

}

5.item布局

<--item_tree-->

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/mTv_Title"
            android:layout_marginTop="@dimen/dp_10"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/c_636363"
            android:layout_marginLeft="@dimen/dp_10"
            android:textSize="@dimen/sp_20" />

        <wanandroid.two.com.wanandroid.widget.FlowLayout
            android:id="@+id/mFl"
            android:layout_marginLeft="@dimen/dp_10"
            android:layout_marginTop="@dimen/dp_10"
            android:layout_marginBottom="@dimen/dp_10"
            android:layout_marginRight="@dimen/dp_60"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        </wanandroid.two.com.wanandroid.widget.FlowLayout>

        <View
            android:background="@color/c_666"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_1"/>

    </LinearLayout>

    <ImageView
        android:id="@+id/mIv_jump"
        android:src="@drawable/u"
        android:layout_alignParentRight="true"
        android:layout_marginRight="@dimen/dp_20"
        android:layout_centerInParent="true"
        android:layout_width="@dimen/dp_20"
        android:layout_height="@dimen/dp_20" />


</RelativeLayout>
<--item_label-->

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:maxLines="1"
    android:ellipsize="end"
    android:gravity="center"
    android:text="@string/app_name"
    android:textColor="@color/c_B6B2B2"
    android:textSize="@dimen/sp_14"/>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陨簇,一起剝皮案震驚了整個(gè)濱河市喇聊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饲窿,老刑警劉巖蔽午,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件樟遣,死亡現(xiàn)場離奇詭異,居然都是意外死亡姿骏,警方通過查閱死者的電腦和手機(jī)糖声,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來分瘦,“玉大人蘸泻,你說我怎么就攤上這事〕懊担” “怎么了悦施?”我有些...
    開封第一講書人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長去团。 經(jīng)常有香客問我抡诞,道長穷蛹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任昼汗,我火速辦了婚禮肴熏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘顷窒。我一直安慰自己蛙吏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開白布鞋吉。 她就那樣靜靜地躺著鸦做,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谓着。 梳的紋絲不亂的頭發(fā)上泼诱,一...
    開封第一講書人閱讀 51,231評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音赊锚,去河邊找鬼坷檩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛改抡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播系瓢,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼阿纤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了夷陋?” 一聲冷哼從身側(cè)響起欠拾,我...
    開封第一講書人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎骗绕,沒想到半個(gè)月后藐窄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酬土,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年荆忍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撤缴。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡刹枉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屈呕,到底是詐尸還是另有隱情微宝,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布虎眨,位于F島的核電站蟋软,受9級(jí)特大地震影響镶摘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岳守,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一凄敢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棺耍,春花似錦贡未、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至害幅,卻和暖如春消恍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背以现。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來泰國打工狠怨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邑遏。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓佣赖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親记盒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子憎蛤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354