imooc學習筆記——流式佈局和熱門標籤
阿新 • • 發佈:2019-02-13
在看imooc打造Android中的流式佈局和熱門標籤這個課程時,感覺沒有什麼太大難度,但是一練習就發現有很多問題會不斷出現,於是就有了這個筆記…..
個人筆記,個人理解 , 如有錯誤歡迎指正
要想實現流式佈局 Android中沒有現成的控制元件,所以需要我們自己寫,也就傳說中的自定義View啦!
對自定義View的瞭解不是很多, 目前我的理解是
1、 繼承View或者ViewGroup (或者其子類)
2、 根據需要重寫其方法
3、 使用
其實這三點就是廢話。。。。但也的確就是這樣的=.=
繼承
流式佈局 應該都見過,它是要放控制元件的容器,所以不能繼承View 必須繼承ViewGroup或其子類
視訊中繼承的是ViewGroup 至於為什麼不繼承RelativeLayout、LinearLayout、FrameLayout 我也沒有想太明白。。。。
繼承後必須實現protected void onLayout(boolean changed, int l, int t, int r, int b) {} 和 幾個構造器
onLayout 這個方法是設定子view的位置 ,那麼設定位置的前提 是要知道要設定子view的大小吧
那麼需要用到onMeasure方法, 這個是測量子View和自身的寬高
如果想要知道子View的一些引數那麼得需要 子view.getLayoutParams
我們可能會需要子View的margin,然而能獲取子ViewMargin 的是ViewGroup.MarginLayoutParams這個類,
所以我們子view的父容器(也就是我們自定義的ViewGroup)必須返回子View一個ViewGroup.MarginLayoutParams型別的LayoutParams,怎麼返回呢
這個方法是在public LayoutParams generateLayoutParams(AttributeSet attrs) {}中返回的
OK,繼承如下
public class MyGroupView extends ViewGroup {
public MyGroupView(Context context) {
this(context, null);
}
public MyGroupView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyGroupView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return super.generateLayoutParams(attrs);
}
}
重寫
1、重寫generateLayoutParams,讓其返回MarginLayoutParams型別,這樣子View才可獲取Margin
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
2、重寫onMeasure,這樣才可以知道ViewGroup應該繪製多大
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width_size = MeasureSpec.getSize(widthMeasureSpec);
int height_size = MeasureSpec.getSize(heightMeasureSpec);
int width_mode = MeasureSpec.getMode(widthMeasureSpec);
int height_mode = MeasureSpec.getMode(heightMeasureSpec);
int width = 0, height = 0, line_width = 0, line_height = 0;
int mCount = getChildCount();
int viewWidth = 0, viewHeight = 0;
//遍歷ChildView 獲得 width 和height
for (int i = 0; i < mCount; i++) {
View view = getChildAt(i);
measureChild(view, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
viewWidth = params.leftMargin + params.rightMargin + view.getMeasuredWidth();
viewHeight = params.topMargin + params.bottomMargin + view.getMeasuredHeight();
if (line_width + viewWidth > width_size - getPaddingRight() - getPaddingLeft()) {//換行
width = Math.max(width, line_width);//寬度為最寬的行寬
height += line_height;//高度累加
//清除以前的寬高
line_width = viewWidth ;
line_height = viewHeight;
} else {//無需換行
line_width += viewWidth;//累加
line_height = Math.max(line_height, viewHeight);//高度為最高的行高
}
if (i == mCount - 1) {//最後一個控制元件
width = Math.max(width, line_width);//寬度為最寬的行寬
height += line_height;//高度累加
}
}
setMeasuredDimension(//如果是EXACTLY設定原來大小,如果不是則設定計算後的大小
width_mode == MeasureSpec.EXACTLY ? width_size : width + getPaddingRight() + getPaddingLeft(),//
height_mode == MeasureSpec.EXACTLY ? height_size : height + getPaddingTop() + getPaddingBottom()//
);
}
3、重寫onLayout,開始分配每個子View的位置
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int line_width = getPaddingLeft(), line_height = 0;
int mCount = getChildCount();
int left = 0, top = getPaddingTop();
//遍歷ChildView
for (int i = 0; i < mCount; i++) {
View view = getChildAt(i);
//獲得子View屬性
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
int viewWidth = params.leftMargin + params.rightMargin + view.getMeasuredWidth();
int viewHeight = params.topMargin + params.bottomMargin + view.getMeasuredHeight();
if (line_width + viewWidth > getWidth() - getPaddingLeft()) {//換行
left = getPaddingLeft();
top += line_height;//高度累加
view.layout(left + params.leftMargin, top + params.topMargin,
left + view.getMeasuredWidth() + params.rightMargin,
top + view.getMeasuredHeight() + params.bottomMargin);
//清除寬高
line_width = viewWidth + getPaddingLeft();
line_height = viewHeight;
} else {//無需換行
left = line_width;
//為
view.layout(left + params.leftMargin, top + params.topMargin,
left + view.getMeasuredWidth() + params.rightMargin,
top + view.getMeasuredHeight() + params.bottomMargin);
line_width += viewWidth;//累加行寬
line_height = Math.max(line_height, viewHeight);//高度為最高的控制元件高度
}
}
}
使用
使用方法很簡單啦
就是在佈局檔案中新增進去就好了
<包名.自定義ViewGroup名>
比如我的就是這樣
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<sunshine.myview.MyGroupView
android:id="@+id/view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#f00"
android:padding="20dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ccc">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#ca0"
android:text="New Button" />
</LinearLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="111" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="111aa1a11111" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="111" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="111" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ccc"
android:gravity="center"
android:padding="10dp"
android:text="aaaaaaaa" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NNNNNNNNNNNNssssNNNNaaaaaaaaaaaaaaaaNNNaaaa" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="New Button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="111" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Neon" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#cc0"
android:gravity="center"
android:padding="10dp"
android:text="aaaa" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ccc"
android:gravity="center"
android:padding="10dp"
android:text="aaaaaaaaaaaaaaaaaaaaassaaaaassddddaa" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NBonssss" />
</sunshine.myview.MyGroupView>
</LinearLayout>
少年,加油吧!