使用Adapter設計模式打造一個流式佈局FlowLayout
流式佈局可以說是在各種軟體中的出場率都很高的一個佈局方式,被廣泛使用,像一些關鍵字搜尋,標籤等等的場景,更是隨處可見,今天我們就來手把手打造一個FlowLayout。
FlowLayout由於是以一個容器的身份存在的,所以其需要繼承的是ViewGroup而不是View,也就是說,我們今天所要做的,就是去自定義一個ViewGroup。
自定義ViewGroup和自定義View的套路基本都是一致的,但也有部分差異,下面,我們先來說說自定義ViewGroup的套路的幾個關鍵點:
自定義屬性(這個就不說了,在之前的文章中已經說了很多次了)
實現onMeasure()方法,通過測量每一個子View的寬高,來計算自身的寬高,最後達到測量自身寬高的目的。
實現onLayout()方法,該方法用於按照自己的想法來擺放可見(不為GONE)的子View。
實現onDraw()方法,默然情況下繼承ViewGroup是不會呼叫該方法的,如果需要繪製一些介面,可以實現dispatchDraw()方法
注意點:在確定要自定義ViewGroup的時候,可以先考慮下先繼承自一些已經封裝好的ViewGroup,如LinearLayout等進行開發。
好了,下面,我們開始自定義FlowLayout
首先,自定義屬性這一塊,我們就直接忽略了,直接從onMeasure方法開始做起(判斷view.visibility != GONE,之前忘加了):
/**
* 測量該控制元件的寬高
* 思路:通過測量每一個子view的寬高 來得到該layout的整體寬高
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 解決onMeasure被呼叫多次,導致在擺放子View的時候出現多次擺放的情況
*/
mChildViews.clear();
//獲取子View的數量
int childCount = getChildCount();
//獲取該layout的寬度 以方便控制後面TAG的擺放 和計算該Layout的高度
int width = MeasureSpec.getSize(widthMeasureSpec);
//初始化layout的高度
int height = getPaddingTop() + getPaddingBottom();
int lineWidth = getPaddingLeft();
//初始化一個每一行的高度 計算layout的總高度時,取每一行的最高
int maxHeight = 0;
ArrayList<View> views = new ArrayList<>();
mChildViews.add(views);
//for迴圈測量子View
for(int i = 0;i < childCount; i++){
View childView = getChildAt(i);
measureChild(childView,widthMeasureSpec,heightMeasureSpec);
ViewGroup.MarginLayoutParams params = (MarginLayoutParams) childView.getLayoutParams();
//當疊加的寬度大於該Layout的總寬度時,則換行
if((lineWidth + childView.getMeasuredWidth() + params.leftMargin + params.rightMargin) > width){
maxHeight = Math.max(maxHeight,childView.getMeasuredHeight() + params.topMargin + params.bottomMargin);
height += maxHeight;
lineWidth = getPaddingLeft() + childView.getMeasuredWidth() + params.leftMargin + params.rightMargin;
views = new ArrayList<>();
mChildViews.add(views);
views.add(childView);
}else{
maxHeight = Math.max(maxHeight,childView.getMeasuredHeight() + params.topMargin + params.bottomMargin);
lineWidth += childView.getMeasuredWidth() + params.leftMargin + params.rightMargin;
views.add(childView);
}
}
height += maxHeight;
setMeasuredDimension(width,height);
}
在計算寬度時,我們需要獲取到每個子View的margin值,但是由於ViewGroup本身是沒有LayoutParams的,所以這裡模仿了下LinearLayout的方法,來獲取MarginLayoutParams:
/**
* 重寫ViewGroup的該方法 獲取到margin值(可以模仿LinearLayout)
* @param attrs
* @returnop
*/
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(),attrs);
}
在onMeasure方法中,當幾個子View的寬度總和大於FlowLayout的寬度時,這個時候就需要換行。其他的,註釋應該都有了!
下一步,就是實現onLayout()方法,來擺放所有的子View(判斷view.visibility != GONE,之前忘加了)
“`
/**
* 擺放子view
* @param changed
* @param l
* @param t
* @param r
* @param b
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int maxHeight,left,right,top,bottom;
top = getPaddingTop();
//迴圈遍歷mChildViews
for(ArrayList<View> views : mChildViews){
left = getPaddingLeft();
maxHeight = 0;
for(int i = 0;i<views.size();i++){
View childView = views.get(i);
ViewGroup.MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams();
maxHeight = Math.max(maxHeight,childView.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin);
left += marginLayoutParams.leftMargin;
right = left + childView.getMeasuredWidth();
int childTop = top + marginLayoutParams.topMargin;
bottom = childTop + childView.getMeasuredHeight();
childView.layout(left,childTop,right,bottom);
left += marginLayoutParams.rightMargin + childView.getMeasuredWidth();
}
top += maxHeight;
}
}
到這裡呢,基本是這個流式佈局就完成了一大半了,下面要做的,就是往這個佈局裡面扔資料,測試其是否會按照我們既定的規則擺放。
在設定資料這一步,我們使用了Adapter的設計模式。下面來看具體的步驟:
1:定義一個抽象的BaseAdapter
/**
* Created by DELL on 2017/9/9.
* Description :
*/
public abstract class BaseAdapter {
//獲取view的數量
public abstract int getCount();
//獲取View
public abstract View getView(int position, ViewGroup parent);
}
這邊暫時只定義了兩個方法,一個是獲取子View數量的,另外一個是獲取到每一個子View的,暫時沒有定義notifySetDataChanged等方法,這個可以根據自己的需求,給其設定一個觀察者來處理。
下一步,需要在FloawLayout中去設定Adapter達到添加布局的效果
public void setAdapter(BaseAdapter adapter){
//當Adapter為空的時候,丟擲異常
if(adapter == null){
throw new NullPointerException("adapter not null");
}
this.mAdapter = adapter;
int count = mAdapter.getCount();
for(int i = 0;i<count;i++){
View view = mAdapter.getView(i,this);
addView(view);
}
}
每一個子View的佈局:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_textview"
android:padding="10dp"
android:layout_margin="5dp"
>
</TextView>
子view背景程式碼:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:color="@color/colorAccent" android:width="1dp"/>
<corners android:radius="8dp"/>
</shape>
下面,在Activity中設定Adapter,來測試下效果:
public class MainActivity extends AppCompatActivity {
private FlowLayout mFlowLayout;
private ArrayList<String> mStrList;
private LayoutInflater mLayoutInflater;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData(){
mStrList = new ArrayList<>();
mStrList.add("JUSTH HELLO!");
mStrList.add("JUSTH HEJUSTH HELLO!LLO!");
mStrList.add("JUSTH LLO!");
mStrList.add("JUSTH HEJUSTH HELLO!LLO!");
mStrList.add("JUSTH HELLO!");
mStrList.add("JUSTLO!");
mStrList.add("JUSTH HELLO!");
mStrList.add("JUSTH HEJUSTH HELLO!LLO!");
mStrList.add("JUSTH HELO!");
mStrList.add("JUSTH HELLO!");
}
private void initView() {
mFlowLayout = (FlowLayout) findViewById(R.id.taglayout);
mLayoutInflater = LayoutInflater.from(this);
mFlowLayout.setAdapter(new BaseAdapter() {
@Override
public int getCount() {
return mStrList.size();
}
@Override
public View getView(int position, ViewGroup parent) {
View view = mLayoutInflater.inflate(R.layout.layout_textview,parent,false);
((TextView)view.findViewById(R.id.item_textview)).setText(mStrList.get(position));
return view;
}
});
}
}
最後,來一波效果圖吧:
相關推薦
使用Adapter設計模式打造一個流式佈局FlowLayout
流式佈局可以說是在各種軟體中的出場率都很高的一個佈局方式,被廣泛使用,像一些關鍵字搜尋,標籤等等的場景,更是隨處可見,今天我們就來手把手打造一個FlowLayout。 FlowLayout由於是以一個容器的身份存在的,所以其需要繼承的是ViewGroup而不是
100行Android程式碼自定義一個流式佈局-FlowLayout
首先來看一下 手淘HD - 商品詳情 - 選擇商品屬性 頁面的UI 商品有很多尺碼,而且展現每個尺碼所需要的View的大小也不同(主要是寬度),所以在從伺服器端拉到資料之前,展現所有尺碼所需要的行數和每一行的個數都無法確定,因此不能直接使用GridView
解決:Android中常見的熱門標籤的流式佈局flowlayout不能wrap_content
最近在專案中藥使用流式佈局,但是在網上找的都不能滿足要求,這篇部落格內容只支援match_parent,我改後的程式碼可以支援wrap_content,原文也僅僅是少加一行高度而已。。新部落格希望大家多多評論。。原文連結 一:概述: 1.流式佈局的特點以
Android中的封裝流式佈局FlowLayout
鴻洋的GitHub:https://github.com/hongyangAndroid/FlowLayout 第一步:加依賴 implementation 'com.hyman:flowlayout-lib:1.1.2' 第二步:建立一個Adapter繼承TagAdapter pu
Android 流式佈局FlowLayout 實現關鍵字標籤
1.介紹 流式佈局的應用還是很廣泛的,比如搜尋熱詞、關鍵詞標籤等,GitHub上已經有很多這樣的佈局了,但是還是想著自己實現一下,最近一直在學自定義控制元件,也鞏固一下所學的知識。 本文實現的效果如下圖所示: 2.思路 繼承自RelativeL
Android開發流式佈局FlowLayout
先說說我的需求吧,我需要做商品規格選擇、類似淘寶京東選擇產品加入購物車。沒辦法只有選擇流式佈局了。最後在改造張鴻洋前輩的Flowlayout實現了該功能。我說說怎麼快速使用流式佈局吧,自定義控制元件說明看這張鴻洋的部落格:http://blog.csdn.net/lmj62
Android流式佈局FlowLayout
現在商城類的APP幾乎都要用到流式佈局來實現選擇屬性功能,在我的demo中是通過FlowLayout工具類實現流式佈局 使用起來非常簡單,十幾行程式碼就可以實現; 在我們的專案中大部分都是單選效果,為了防止用到多選,demo中也實現了多選; FlowLayout大家不用研
自定義控制元件之-流式佈局FlowLayout
前言 其實對於流式佈局控制元件,很多人並不陌生,專案中或多或少都會用到的.但是有多少人會寫一個流式佈局的控制元件這就不知道了,所以博主這裡對流式佈局進行一個講解,並且封裝一個比較完善的控制元件 效果圖 看到的這個整個就是一個流式佈局,裡面是
流式佈局 FlowLayout 的簡單使用
先給大家看效果圖:歷史記錄本地儲存到share裡面,在onStart裡面獲取呼叫資料,點選搜尋的時候新增進share。匯入依賴:compile 'com.nex3z:flow-layout:1.2.2'https://github.com/nex3z/FlowLayoutUs
Android 實現一個簡易橫向流式佈局
SimpleFlowLayout:一個簡易的橫向流式佈局,只實現核心功能,使用者可自行擴充套件 Demo圖片如下所示: SimpleFlowLayout直接繼承自ViewGroup,主要負責
二十九、Java圖形化介面設計——佈局管理器之FlowLayout(流式佈局)
前文講解了JFrame、JPanel,其中已經涉及到了空佈局的使用。Java雖然可以以畫素為單位對元件進行精確的定位,但是其在不同的系統中將會有一定的顯示差異,使得顯示效果不盡相同,為此java提供了佈局管理器,以使編寫的圖形介面具有良好的平臺無關性。
跟我學JAVA(5)圖形化介面設計——佈局管理器之FlowLayout(流式佈局)
一、佈局管理器所屬類包 所屬類包 佈局管理器名稱 說明 Java.awt FlowLayout(流式佈局) 元件按照加入的先後順序按照設定的對齊方式從左向右排列,一
一個非常好用的Android流式佈局
效果圖鎮樓 首先我們先新增依賴 compile 'com.zhy:flowlayout-lib:1.0.3' 然後將以下標籤和佈局新增到專案中。 主佈局layouy->activity_flow_layout.xml <?xml v
自定義View,流式佈局,
寫的比較基礎, 備忘使用。 public class FlowLayout extends ViewGroup { public FlowLayout(Context context) { this(context, null); }
流式佈局簡單實現
//主方法 //建立集合 private List<String> mStrings=new ArrayList<>(); final EditText ed_search=(EditText)findViewById(R.id.ed_search
設計模式 _第二招式_工廠方法模式
一、定義 工廠方法模式使用的頻率非常高,在我們日常的開發中總能看到它的身影。其定義為:定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工程方法使用一個類的例項化延遲到其子類。 二、程式碼演示 在工廠方法模式中, 抽象產品類Product負責定義產品的共性,實現對事物最抽象的定
設計模式 _第一招式_單例模式
一、定義 單例模式(Singleton Pattern)是一個比較簡單的模式,確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。 二、程式碼演示 Singleton 類稱為單例類,通過使用private的建構函式確保在一個應用中只產生一個例項,並且自行例項化,單例
流式佈局 佈局xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app=
笨鳥兒 靜態佈局、自適應佈局、流式佈局、響應式佈局、彈性佈局等的概念和區別
一、靜態佈局(Static Layout) 即傳統Web設計,網頁上的所有元素的尺寸一律使用px作為單位。 1、佈局特點:不管瀏覽器尺寸具體是多少,網頁佈局始終按照最初寫程式碼時的佈局來顯示。常規的pc的網站都是靜態(定寬度)佈局的,也就是設定了min-width,這樣的話,如果小於這個寬度就會
Flex佈局實戰(二):網格 \ 聖盃 \ 輸入框 \ 懸掛式 \ 固定底欄 \ 流式佈局
參考:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html 下面程式碼可能會比較多,但核心CSS程式碼已經用 /**/ 的標記標出,直接看核心程式碼就好。 一、網格佈局 1、基本網格佈局 最簡單