【應用場景】:熱門標簽、推薦 【特點】: 在佈局內,隨意擺放任意個view,每行所擺放的view個數,根據實施計算出來的寬度,一旦當前要擺放的view寬度和之前擺放的所有view寬度加在一起,超過了佈局的寬度,那麼就把該view換行擺放。 【佈局】: <LinearLayout xmlns:andr ...
【應用場景】:熱門標簽、推薦
【特點】:
在佈局內,隨意擺放任意個view,每行所擺放的view個數,根據實施計算出來的寬度,一旦當前要擺放的view寬度和之前擺放的所有view寬度加在一起,超過了佈局的寬度,那麼就把該view換行擺放。
【佈局】:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.atguigu.p2pinvest0520.ui.FlowLayout
android:id="@+id/flow_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple">
</com.atguigu.p2pinvest0520.ui.FlowLayout>
</LinearLayout>
【自定義FlowLayout】:
public class FlowLayout extends ViewGroup {
public FlowLayout(Context context) {
this(context, null);
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲取寬度和高度的模式和數值
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//如果是至多模式,需要我們自己去測量佈局的寬度和高度
int width = 0;
int height = 0;
//聲明一行的寬度和高度
int lineWidth = 0;
int lineHeight = 0;
//獲取子視圖的個數
int childCount = getChildCount();
for(int i = 0;i < childCount;i++){
//獲取每一個子視圖的寬度和高度,邊距值
View childView = getChildAt(i);
//需要調用如下的方法之後,才可以獲取子視圖的寬高
measureChild(childView,widthMeasureSpec,heightMeasureSpec);
//獲取測量的寬高
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
//獲取邊距(要想獲取邊距,必須重寫當前類的方法generateLayoutParams())
MarginLayoutParams mp = (MarginLayoutParams) childView.getLayoutParams();
if(lineWidth + childWidth + mp.leftMargin + mp.rightMargin <= widthSize){//不換行
lineWidth += childWidth + mp.leftMargin + mp.rightMargin;
lineHeight = Math.max(lineHeight,childHeight + mp.topMargin + mp.bottomMargin);
}else{//換行
width = Math.max(width,lineWidth);
height += lineHeight;
//重置
lineWidth = childWidth + mp.leftMargin + mp.rightMargin;
lineHeight = childHeight + mp.topMargin + mp.bottomMargin;
}
//單獨的考慮一下最後一個!
if(i == childCount - 1){
width = Math.max(width,lineWidth);
height += lineHeight;
}
}
Log.e("TAG", "widthSize = " + widthSize + ",heightSize = " + heightSize);
Log.e("TAG", "width = " + width + ",height = " +height);
//設置當前佈局的寬高
setMeasuredDimension(widthMode == MeasureSpec.EXACTLY? widthSize : width,
heightMode == MeasureSpec.EXACTLY ? heightSize : height);
}
private List<Integer> allHeights = new ArrayList<>();//每一行的高度構成的集合
private List<List<View>> allViews = new ArrayList<>();//每一行view集合構成的集合
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = getWidth();//獲取佈局的寬度
//每一行的寬度和高度
int lineWidth = 0;
int lineHeight = 0;
int childCount = getChildCount();
List<View> lineViews = new ArrayList<>();//用於保存一行的所有的View
//目的:給allHeights 和 allViews 賦值
for(int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
MarginLayoutParams mp = (MarginLayoutParams) childView.getLayoutParams();
if(lineWidth + childWidth + mp.leftMargin + mp.rightMargin <= width){//不換行
lineWidth += childWidth + mp.leftMargin + mp.rightMargin;
lineHeight = Math.max(lineHeight,childHeight + mp.topMargin + mp.bottomMargin);
lineViews.add(childView);
}else{//換行
allHeights.add(lineHeight);
allViews.add(lineViews);
lineViews = new ArrayList<>();
lineViews.add(childView);
lineWidth = childWidth + mp.leftMargin + mp.rightMargin;
lineHeight = childHeight + mp.topMargin + mp.bottomMargin;
}
//單獨考慮最後一個元素
if(i == childCount - 1){
allViews.add(lineViews);
allHeights.add(lineHeight);
}
}
Log.e("TAG", "allViews.size = " + allViews.size() + "allHeight.size = " + allHeights.size());
int lineNumber = allViews.size();
int x = 0;
int y = 0;
for(int i = 0; i < lineNumber; i++) {
List<View> singleLineViews = allViews.get(i);//獲取一行中元素構成的集合
int singleLineHeight = allHeights.get(i);//獲取一行的高度
for(View view : singleLineViews){//遍歷一行元素
MarginLayoutParams mp = (MarginLayoutParams) view.getLayoutParams();
int left = x + mp.leftMargin;
int top = y + mp.topMargin;
int right = left + view.getMeasuredWidth();
int bottom = top + view.getMeasuredHeight();
view.layout(left,top,right,bottom);
x += view.getMeasuredWidth() + mp.leftMargin + mp.rightMargin;
}
//換行
x = 0;
y += singleLineHeight;
}
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
MarginLayoutParams mp = new MarginLayoutParams(getContext(), attrs);
return mp;
}
}
【動態添加TextView】
public class ProductHotFragment extends BaseFragment {
@Bind(R.id.flow_layout)
FlowLayout flowLayout;
//提供頁面要顯示的數據
private String[] datas = new String[]{"新手計劃", "樂享活系列90天計劃", "錢包", "30天理財計劃(加息2%)",
"林業局投資商業經營與大撈一筆", "中學老師購買車輛", "屌絲下海經商計劃", "新西游影視拍",
"Java培訓老師自己周轉", "HelloWorld", "C++-C-ObjectC-java", "Android vs ios", "演算法與數據結構", "JNI與NDK", "team working"};
private Random random;
@Override
protected RequestParams getParams() {
return null;
}
@Override
protected String getUrl() {
return null;
}
@Override
protected void initData(String content) {
random = new Random();
//1.動態的創建TextView
for(int i = 0; i < datas.length; i++) {
final TextView tv = new TextView(getActivity());
//設置TextView的屬性
tv.setText(datas[i]);
tv.setTextSize(UIUtils.dp2Px(10));
ViewGroup.MarginLayoutParams mp = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
mp.leftMargin = UIUtils.dp2Px(8);
mp.rightMargin = UIUtils.dp2Px(8);
mp.topMargin = UIUtils.dp2Px(8);
mp.bottomMargin = UIUtils.dp2Px(8);
tv.setLayoutParams(mp);
//設置textView的背景
int red = random.nextInt(211);
int green = random.nextInt(211);
int blue = random.nextInt(211);
//測試一:
// tv.setBackground(DrawUtils.getDrawable(Color.rgb(red,green,blue),UIUtils.dp2Px(5)));
//測試二:
tv.setBackground(DrawUtils.getSelector(DrawUtils.getDrawable(Color.rgb(red, green, blue),UIUtils.dp2Px(5)),DrawUtils.getDrawable(Color.WHITE,UIUtils.dp2Px(5))));
//保存按下能顯示selector的效果,需要設置一個如下的屬性
// tv.setClickable(true);
//添加點擊事件,也是實現顯示selector的效果的一種方式
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(ProductHotFragment.this.getActivity(), tv.getText(), Toast.LENGTH_SHORT).show();
}
});
//設置內邊距
int padding = UIUtils.dp2Px(5);
tv.setPadding(padding,padding,padding,padding);
// 2.添加到FlowLayout佈局中
flowLayout.addView(tv);
}
}
@Override
protected void initTitle() {
}
@Override
public int getLayoutId() {
return R.layout.fragment_product_hot;
}
}