整體過一下認(rèn)識的類
除去attr包以外卓囚,我們一起看下哪些我們說過
我們一起回顧下
- 入口是 AutoLayoutActivity:
- 簡單處理奶镶,把
LinearLayout -> AutoLinearLayout
RelativeLayout -> AutoRelativeLayout
FrameLayout -> AutoFrameLayout
-
AutoLinearLayout,AutoRelativeLayout洛勉,AutoFrameLayout簡單實現(xiàn)
- 通過 關(guān)聯(lián)和依賴 AutoLayoutHelper, 來連接
- AutoLayoutInfo對象
- (自己的靜態(tài)內(nèi)部類LayoutParams中 通過AutoLayoutHelper實現(xiàn)返回)
-
獲取Manifest中信息AutoLayoutConifg
- 通過依賴 PackageManager, ApplicationInfo獲取 design的寬高
- 通過 ScreenUtils 來獲取屏幕寬高
其他類
除去attr包以外盯捌,哪些還沒有用過
- L
public class L
{
public static boolean debug = false;
private static final String TAG = "AUTO_LAYOUT";
public static void e(String msg)
{
if (debug)
{
Log.e(TAG, msg);
}
}
}
可以發(fā)現(xiàn),只是一個打印控制類
UseLandscape
public interface UseLandscape
{
}
- 只是空的蘑秽,可能是預(yù)留以后寫的吧
- AutoUtils
public class AutoUtils{
public static void auto(View view)
{
autoSize(view);
autoPadding(view);
autoMargin(view);
}
public static void autoMargin(View view)
{
if (!(view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams))
return;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
if (lp == null) return;
Object tag = view.getTag(R.id.id_tag_autolayout_margin);
if (tag != null) return;
view.setTag(R.id.id_tag_autolayout_margin, "Just Identify");
lp.leftMargin = getPercentWidthSize(lp.leftMargin);
lp.topMargin = getPercentHeightSize(lp.topMargin);
lp.rightMargin = getPercentWidthSize(lp.rightMargin);
lp.bottomMargin = getPercentHeightSize(lp.bottomMargin);
}
public static void autoPadding(View view)
{
Object tag = view.getTag(R.id.id_tag_autolayout_padding);
if (tag != null) return;
view.setTag(R.id.id_tag_autolayout_padding, "Just Identify");
int l = view.getPaddingLeft();
int t = view.getPaddingTop();
int r = view.getPaddingRight();
int b = view.getPaddingBottom();
l = getPercentWidthSize(l);
t = getPercentHeightSize(t);
r = getPercentWidthSize(r);
b = getPercentHeightSize(b);
view.setPadding(l, t, r, b);
}
public static void autoSize(View view)
{
ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp == null) return;
Object tag = view.getTag(R.id.id_tag_autolayout_size);
if (tag != null) return;
view.setTag(R.id.id_tag_autolayout_size, "Just Identify");
if (lp.width > 0)
{
int screenWidth = AutoLayoutConifg.getInstance().getScreenWidth();
int designWidth = AutoLayoutConifg.getInstance().getDesignWidth();
lp.width = (int) (lp.width * 1.0f / designWidth * screenWidth);
}
if (lp.height > 0)
{
int screenHeight = AutoLayoutConifg.getInstance().getScreenHeight();
int designHeight = AutoLayoutConifg.getInstance().getDesignHeight();
lp.height = (int) (lp.height * 1.0f / designHeight * screenHeight);
}
}
public static int getPercentWidthSize(int val)
{
int screenWidth = AutoLayoutConifg.getInstance().getScreenWidth();
int designWidth = AutoLayoutConifg.getInstance().getDesignWidth();
return (int) (val * 1.0f / designWidth * screenWidth);
}
public static int getPercentWidthSizeBigger(int val)
{
int screenWidth = AutoLayoutConifg.getInstance().getScreenWidth();
int designWidth = AutoLayoutConifg.getInstance().getDesignWidth();
int res = val * screenWidth;
if (res % designWidth == 0)
{
return res / designWidth;
} else
{
return res / designWidth + 1;
}
}
public static int getPercentHeightSizeBigger(int val)
{
int screenHeight = AutoLayoutConifg.getInstance().getScreenHeight();
int designHeight = AutoLayoutConifg.getInstance().getDesignHeight();
int res = val * screenHeight;
if (res % designHeight == 0)
{
return res / designHeight;
} else
{
return res / designHeight + 1;
}
}
public static int getPercentHeightSize(int val)
{
int screenHeight = AutoLayoutConifg.getInstance().getScreenHeight();
int designHeight = AutoLayoutConifg.getInstance().getDesignHeight();
return (int) (val * 1.0f / designHeight * screenHeight);
}
}
我們發(fā)現(xiàn)都是靜態(tài)方法饺著,應(yīng)該就只是一個幫助類了
- MetroLayout
public class MetroLayout extends ViewGroup
{
private final AutoLayoutHelper mHelper = new AutoLayoutHelper(this);
private static class MetroBlock
{
int left;
int top;
int width;
}
private List<MetroBlock> mAvailablePos = new ArrayList<>();
private int mDivider;
public MetroLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MetroLayout);
mDivider = a.getDimensionPixelOffset(R.styleable.MetroLayout_metro_divider, 0);
mDivider = AutoUtils.getPercentWidthSizeBigger(mDivider);
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (true)
randomColor();
if (!isInEditMode())
mHelper.adjustChildren();
measureChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void randomColor()
{
Random r = new Random(255);
for (int i = 0, n = getChildCount(); i < n; i++)
{
View v = getChildAt(i);
v.setBackgroundColor(Color.argb(100, r.nextInt(), r.nextInt(), r.nextInt()));
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
initAvailablePosition();
int left = 0;
int top = 0;
int divider = mDivider;
for (int i = 0, n = getChildCount(); i < n; i++)
{
View v = getChildAt(i);
if (v.getVisibility() == View.GONE) continue;
MetroBlock newPos = findAvailablePos(v);
left = newPos.left;
top = newPos.top;
int childWidth = v.getMeasuredWidth();
int childHeight = v.getMeasuredHeight();
int right = left + childWidth;
int bottom = top + childHeight;
v.layout(left, top, right, bottom);
if (childWidth + divider < newPos.width)
{
newPos.left += childWidth + divider;
newPos.width -= childWidth + divider;
} else
{
mAvailablePos.remove(newPos);
}
MetroBlock p = new MetroBlock();
p.left = left;
p.top = bottom + divider;
p.width = childWidth;
mAvailablePos.add(p);
mergeAvailablePosition();
}
}
private void mergeAvailablePosition()
{
if (mAvailablePos.size() <= 1) return;
List<MetroBlock> needRemoveBlocks = new ArrayList<>();
MetroBlock one = mAvailablePos.get(0);
MetroBlock two = mAvailablePos.get(1);
for (int i = 1, n = mAvailablePos.size(); i < n - 1; i++)
{
if (one.top == two.top)
{
one.width = one.width + two.width;
needRemoveBlocks.add(one);
two.left = one.left;
two = mAvailablePos.get(i + 1);
} else
{
one = mAvailablePos.get(i);
two = mAvailablePos.get(i + 1);
}
}
mAvailablePos.removeAll(needRemoveBlocks);
}
private void initAvailablePosition()
{
mAvailablePos.clear();
MetroBlock first = new MetroBlock();
first.left = getPaddingLeft();
first.top = getPaddingTop();
first.width = getMeasuredWidth();
mAvailablePos.add(first);
}
private MetroBlock findAvailablePos(View view)
{
MetroBlock p = new MetroBlock();
if (mAvailablePos.size() == 0)
{
p.left = getPaddingLeft();
p.top = getPaddingTop();
p.width = getMeasuredWidth();
return p;
}
int min = mAvailablePos.get(0).top;
MetroBlock minHeightPos = mAvailablePos.get(0);
for (MetroBlock _p : mAvailablePos)
{
if (_p.top < min)
{
min = _p.top;
minHeightPos = _p;
}
}
return minHeightPos;
}
@Override
public MetroLayout.LayoutParams generateLayoutParams(AttributeSet attrs)
{
return new LayoutParams(getContext(), attrs);
}
public static class LayoutParams extends ViewGroup.MarginLayoutParams
implements AutoLayoutHelper.AutoLayoutParams
{
private AutoLayoutInfo mAutoLayoutInfo;
public LayoutParams(Context c, AttributeSet attrs)
{
super(c, attrs);
mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);
}
public LayoutParams(int width, int height)
{
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams source)
{
super(source);
}
public LayoutParams(MarginLayoutParams source)
{
super(source);
}
public LayoutParams(LayoutParams source)
{
this((ViewGroup.LayoutParams) source);
mAutoLayoutInfo = source.mAutoLayoutInfo;
}
@Override
public AutoLayoutInfo getAutoLayoutInfo()
{
return mAutoLayoutInfo;
}
}
}
也和前面的AutoXXXLayout類似箫攀,
都只是通過 關(guān)聯(lián)和依賴 AutoLayoutHelper ,
Override對應(yīng)的
onMeasure(int widthMeasureSpec, int heightMeasureSpec) 和 generateLayoutParams(AttributeSet attrs)
通過靜態(tài)內(nèi)部類 的接口幼衰, 傳遞 AutoLayoutHelper的實現(xiàn)
返回 AutoLayoutInfo 對象
這里沒有使用靴跛,所以暫時不考慮
- AutoLayoutHelper
- 這里就是 AutoLayoutHelper 最復(fù)雜
- 很多類都會 關(guān)聯(lián) 和 依賴 它
- 后面單獨分析這個類
AutoLayoutHelper
這里比較復(fù)雜,
我們分別看一下這里面的接口和方法
AutoLayoutParams
public interface AutoLayoutParams
{
AutoLayoutInfo getAutoLayoutInfo();
}
上一篇我們看到對應(yīng)的幾種AutoXXXLayout渡嚣,靜態(tài)內(nèi)部類LayoutParams梢睛,都會實現(xiàn)這個接口
對應(yīng)的實現(xiàn),就是 靜態(tài)方法 getAutoLayoutInfo(Context context,AttributeSet attrs)
AutoLayoutHelper構(gòu)造 和 initAutoLayoutConfig
private static AutoLayoutConifg mAutoLayoutConifg;
public AutoLayoutHelper(ViewGroup host)
{
mHost = host;
if (mAutoLayoutConifg == null)
{
initAutoLayoutConfig(host);
}
}
private void initAutoLayoutConfig(ViewGroup host)
{
mAutoLayoutConifg = AutoLayoutConifg.getInstance();
mAutoLayoutConifg.init(host.getContext());
}
這里识椰,可以發(fā)現(xiàn)绝葡,構(gòu)造只是
傳遞ViewGroup對象,
和
調(diào)用initAutoLayoutConfig方法裤唠,初始化 懶漢單例的AutoLayoutConifg對象
剩下的 2個前面用到的方法
在AutoXXXLayout中
都只是通過 關(guān)聯(lián)和依賴 這里的AutoLayoutHelper
onMeasure(int widthMeasureSpec, int heightMeasureSpec) 中
用到了 mHelper.adjustChildren()
generateLayoutParams(AttributeSet attrs)中
調(diào)用的靜態(tài)內(nèi)部類挤牛,接口的實現(xiàn),其實是構(gòu)造中
mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs) 實現(xiàn)的
這里种蘸,我們分別看下這2個方法
getAutoLayoutInfo(Context context,AttributeSet attrs)
public static AutoLayoutInfo getAutoLayoutInfo(Context context,AttributeSet attrs)
{
AutoLayoutInfo info = new AutoLayoutInfo();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoLayout_Layout);
int baseWidth = a.getInt(R.styleable.AutoLayout_Layout_layout_auto_basewidth, 0);
int baseHeight = a.getInt(R.styleable.AutoLayout_Layout_layout_auto_baseheight, 0);
a.recycle();
TypedArray array = context.obtainStyledAttributes(attrs, LL);
int n = array.getIndexCount();
for (int i = 0; i < n; i++)
{
int index = array.getIndex(i);
// String val = array.getString(index);
// if (!isPxVal(val)) continue;
if (!isPxVal(array.peekValue(index))) continue;
int pxVal = 0;
try
{
pxVal = array.getDimensionPixelOffset(index, 0);
} catch (Exception ignore)//not dimension
{
continue;
}
switch (index)
{
case INDEX_TEXT_SIZE:
info.addAttr(new TextSizeAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_PADDING:
info.addAttr(new PaddingAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_PADDING_LEFT:
info.addAttr(new PaddingLeftAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_PADDING_TOP:
info.addAttr(new PaddingTopAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_PADDING_RIGHT:
info.addAttr(new PaddingRightAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_PADDING_BOTTOM:
info.addAttr(new PaddingBottomAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_WIDTH:
info.addAttr(new WidthAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_HEIGHT:
info.addAttr(new HeightAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MARGIN:
info.addAttr(new MarginAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MARGIN_LEFT:
info.addAttr(new MarginLeftAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MARGIN_TOP:
info.addAttr(new MarginTopAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MARGIN_RIGHT:
info.addAttr(new MarginRightAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MARGIN_BOTTOM:
info.addAttr(new MarginBottomAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MAX_WIDTH:
info.addAttr(new MaxWidthAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MAX_HEIGHT:
info.addAttr(new MaxHeightAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MIN_WIDTH:
info.addAttr(new MinWidthAttr(pxVal, baseWidth, baseHeight));
break;
case INDEX_MIN_HEIGHT:
info.addAttr(new MinHeightAttr(pxVal, baseWidth, baseHeight));
break;
}
}
array.recycle();
L.e(" getAutoLayoutInfo " + info.toString());
return info;
}
這里類中定義了很多靜態(tài)的int值墓赴,用于switch,
也有定義的LL靜態(tài)數(shù)組航瞭,對應(yīng)android中常用的屬性
這里獲得這些常用屬性以后诫硕,for循環(huán)會通過int的靜態(tài)值,switch對應(yīng)的地方
在添加到 容器類 AutoLayoutInfo 的對象中
(也就是 前面提到的接口實現(xiàn)返回的 AutoLayoutInfo 對象)
這里刊侯,每個switch章办,對應(yīng)的一個 Attr 屬性類, 存放在 attr 包中(之前分析單獨忽略的那個package)
具體邏輯滨彻,之后再一起分析
adjustChildren()
public void adjustChildren()
{
AutoLayoutConifg.getInstance().checkParams();
for (int i = 0, n = mHost.getChildCount(); i < n; i++)
{
View view = mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params instanceof AutoLayoutParams)
{
AutoLayoutInfo info =
((AutoLayoutParams) params).getAutoLayoutInfo();
if (info != null)
{
info.fillAttrs(view);
}
}
}
}
這個類藕届,相對于上一個方法,簡單一點
這里會得到對應(yīng)ViewGroup的 子View 個數(shù)亭饵,
for循環(huán)獲取每個 子View的 LayoutParams
如果 params instanceof AutoLayoutParams
也就是說休偶, 是我們前面實現(xiàn)的 接口類型的時候
轉(zhuǎn)型獲取前面接口實現(xiàn)的 AutoLayoutInfo 對象
(就是 上一個 getAutoLayoutInfo(Context context,AttributeSet attrs) 返回的對象)
最后 遍歷 每個子View的 AutoLayoutInfo中每個常用屬性
下一篇我們可以了解鴻洋AutoLayout代碼分析(五):Attr相關(guān)類