編輯:關於Android編程
源碼下載地址:https://github.com/gdutxiaoxu/CustomViewDemo.git
仔細觀察,我們可以知道圖二其實是圖一效果的升級版,圖一當我們控件的寬度超過這一行的時候,剩余的寬度它不會自動分布到每個控件中,而圖二的效果當我們換行的時候,如控件還沒有占滿這一行的時候,它會自動把剩余的寬度分布到每個控件中
`
/**
* 博客地址:http://blog.csdn.net/gdutxiaoxu
* @author xujun
* @time 2016/6/20 23:49.
*/
public class SimpleFlowLayout extends ViewGroup {
private int verticalSpacing = 20;
public SimpleFlowLayout(Context context ) {
super(context);
}
/**
* 重寫onMeasure方法是為了確定最終的大小
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
//處理Padding屬性,讓當前的ViewGroup支持Padding
int widthUsed = paddingLeft + paddingRight;
int heightUsed = paddingTop + paddingBottom;
int childMaxHeightOfThisLine = 0;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
// 已用的寬度
int childUsedWidth = 0;
// 已用的高度
int childUsedHeight = 0;
// 調用ViewGroup自身的方法測量孩子的寬度和高度,我們也可以自己根據MeasureMode來測量
measureChild(child,widthMeasureSpec,heightMeasureSpec);
childUsedWidth += child.getMeasuredWidth();
childUsedHeight += child.getMeasuredHeight();
//處理Margin,支持孩子的Margin屬性
Rect marginRect = getMarginRect(child);
int leftMargin=marginRect.left;
int rightMargin=marginRect.right;
int topMargin=marginRect.top;
int bottomMargin=marginRect.bottom;
childUsedWidth += leftMargin + rightMargin;
childUsedHeight += topMargin + bottomMargin;
//總寬度沒有超過本行
if (widthUsed + childUsedWidth < widthSpecSize) {
widthUsed += childUsedWidth;
if (childUsedHeight > childMaxHeightOfThisLine) {
childMaxHeightOfThisLine = childUsedHeight;
}
} else {//總寬度已經超過本行
heightUsed += childMaxHeightOfThisLine + verticalSpacing;
widthUsed = paddingLeft + paddingRight + childUsedWidth;
childMaxHeightOfThisLine = childUsedHeight;
}
}
}
//加上最後一行的最大高度
heightUsed += childMaxHeightOfThisLine;
setMeasuredDimension(widthSpecSize, heightUsed);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
/**
* 為了 支持Padding屬性
*/
int childStartLayoutX = paddingLeft;
int childStartLayoutY = paddingTop;
int widthUsed = paddingLeft + paddingRight;
int childMaxHeight = 0;
int childCount = getChildCount();
//擺放每一個孩子的高度
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
int childNeededWidth, childNeedHeight;
int left, top, right, bottom;
int childMeasuredWidth = child.getMeasuredWidth();
int childMeasuredHeight = child.getMeasuredHeight();
Rect marginRect = getMarginRect(child);
int leftMargin=marginRect.left;
int rightMargin=marginRect.right;
int topMargin=marginRect.top;
int bottomMargin=marginRect.bottom;
childNeededWidth = leftMargin + rightMargin + childMeasuredWidth;
childNeedHeight = topMargin + topMargin + childMeasuredHeight;
// 沒有超過本行
if (widthUsed + childNeededWidth <= r - l) {
if (childNeedHeight > childMaxHeight) {
childMaxHeight = childNeedHeight;
}
left = childStartLayoutX + leftMargin;
top = childStartLayoutY + topMargin;
right = left + childMeasuredWidth;
bottom = top + childMeasuredHeight;
widthUsed += childNeededWidth;
childStartLayoutX += childNeededWidth;
} else {
childStartLayoutY += childMaxHeight + verticalSpacing;
childStartLayoutX = paddingLeft;
widthUsed = paddingLeft + paddingRight;
left = childStartLayoutX + leftMargin;
top = childStartLayoutY + topMargin;
right = left + childMeasuredWidth;
bottom = top + childMeasuredHeight;
widthUsed += childNeededWidth;
childStartLayoutX += childNeededWidth;
childMaxHeight = childNeedHeight;
}
child.layout(left, top, right, bottom);
}
}
}
private Rect getMarginRect(View child) {
LayoutParams layoutParams = child.getLayoutParams();
int leftMargin = 0;
int rightMargin = 0;
int topMargin = 0;
int bottomMargin = 0;
if (layoutParams instanceof MarginLayoutParams) {
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) layoutParams;
leftMargin = marginLayoutParams.leftMargin;
rightMargin = marginLayoutParams.rightMargin;
topMargin = marginLayoutParams.topMargin;
bottomMargin = marginLayoutParams.bottomMargin;
}
return new Rect(leftMargin, topMargin, rightMargin, bottomMargin);
}
}`
添加完一個孩子以後我們判斷widthUsed是夠超出控件本身的最大寬度widthSpecSize,
若沒有超過執行
widthUsed += childUsedWidth;
if (childUsedHeight > childMaxHeightOfThisLine) {
childMaxHeightOfThisLine = childUsedHeight;
}
超過控件的寬度執行
heightUsed += childMaxHeightOfThisLine + verticalSpacing;
widthUsed = paddingLeft + paddingRight + childUsedWidth;
childMaxHeightOfThisLine = childUsedHeight;
最後調用 setMeasuredDimension(widthSpecSize, heightUsed);這個方法去設置它的大小
3.在OnLayout方法裡面,所做的工作就是去擺放每一個孩子的位置 ,判斷需不需要換行,不需要更改left值,需要換行,更改top值
講解之前,我們先來了解一下一個基本知識
從這張圖片裡面我們可以得出這樣結論
Width=控件真正的寬度(realWidth)+PaddingLeft+PaddingRight margin是子控件相對於父控件的距離注意事項<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4NCjxwPs6qwcvWp7PWv9i8/rG+ye21xHBhZGRpbmfK9NDUo6zO0sPH1/bBy7SmwO2jrNb30qq0+sLryOfPwjwvcD4NCjxwcmUgY2xhc3M9"brush:java;">
為了支持子控件的margin屬性,我們同樣也做了處理 即我們在計算孩子所占用的寬度和高度的時候加上margin屬性的高度,接著在計算需要孩子總共用的寬高度的時候加上每個孩子的margin屬性的寬高度,這樣自然就支持了孩子的margin屬性了 如下圖所見,在控件寬度參差不齊的情況下,控件換行會留下一些剩余的寬度,作為想寫出魯棒性的代碼的我們會覺得別扭,於是我們相處了解決辦法。 解決方法見下面 對比圖一的實現思路,我們封裝了Line這個內部類,看到這個名字,相信大家都猜到是什麼意思了,其實就是一個Line實例對象代表一行,Line裡面的List children用來存放孩子 Line裡面還封裝了void onLayout(int l, int t)方法,即自己去拜訪每個孩子的位置, 源碼下載地址:https://github.com/gdutxiaoxu/CustomViewDemo.git int widthUsed = paddingLeft + paddingRight;
int heightUsed = paddingTop + paddingBottom;
----------
if (widthUsed + childUsedWidth < widthSpecSize) {
widthUsed += childUsedWidth;
if (childUsedHeight > childMaxHeightOfThisLine) {
childMaxHeightOfThisLine = childUsedHeight;
}
}
Rect marginRect = getMarginRect(child);
int leftMargin=marginRect.left;
int rightMargin=marginRect.right;
int topMargin=marginRect.top;
int bottomMargin=marginRect.bottom;
childUsedWidth += leftMargin + rightMargin;
childUsedHeight += topMargin + bottomMargin;
4.缺陷
圖二源碼解析
廢話不多說,先看源碼
/**
* 博客地址:http://blog.csdn.net/gdutxiaoxu
* @author xujun
* @time 2016/6/26 22:54.
*/
public class PrefectFlowLayout extends ViewGroup {
public PrefectFlowLayout(Context context) {
super(context);
}
public PrefectFlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PrefectFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private int parentWidthSize;//父容器寬度
private int horizontalSpacing = 16;//水平間距
private int verticalSpacing = 16;//垂直間距
private Line currentLine;//當前行
private List
2.思路解析
private List
實現剩余的寬度平均分配,主要體現在這幾行代碼
if (surplus > 0) {
//如果有剩余寬度,則將剩余寬度平分給每一個子控件
surplusChild = (int) (surplus / children.size()+0.5);
}
-------
child.measure(MeasureSpec.makeMeasureSpec(child.getMeasuredWidth()+surplusChild,MeasureSpec.EXACTLY)
,MeasureSpec.makeMeasureSpec(height,MeasureSpec.EXACTLY));
今天就寫到這裡了,有時間再來補充,最近考試比較忙,已經好久沒有更新博客了。
Blur自從iOS系統引入了Blur效果,也就是所謂的毛玻璃、模糊化效果,磨砂效果,各大系統就開始競相模仿,這是一個怎樣的效果呢,我們現來看一些圖:這些就是典型的Blur
用戶的聊天背景可以自定義,設置成自己喜歡的圖片,從而讓手機QQ更有個性,更具有個人特色。怎麼設置手機qq背景?手機qq設置聊天背景在哪?下面我們就一起來看看
本文實例講述了Android控件之TabHost用法。分享給大家供大家參考。具體如下:以下通過TabHost實現android選項卡。main.xml布局文件:<&
之前也試過vitamio這個庫,後來不知道被什麼事情給耽擱了,就沒繼續下去。近來覺得視頻還是需要學習一下的,誰讓直播那麼火呢,就想著寫一個簡單的視頻播放的app先吧。好了