热门标签推荐的流式布局

【应用场景】:热门标签、推荐

【特点】:

在布局内,随意摆放任意个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;
}

}

时间: 2024-10-19 04:37:28

热门标签推荐的流式布局的相关文章

Android中常见的热门标签的流式布局的实现

一.概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出) 类似的自定义布局.下面我们就来详细介绍流式布局的应用特点以及用的的技术点: 1.流式布局的特点以及应用场景    特点:当上面一行的空间不够容纳新的TextView时候,    才开辟下一行的空间 原理图: 场景:主要用于关键词搜索或者热门标签等场景2.自定义ViewGroup,重点重写下面两个方法 1.o

Android流式布局实现

查看我的全部开源项目[开源实验室] 欢迎加入我的QQ群:[201055521],本博客客户端下载[请点击] 摘要 新项目用到了一种全新布局----Android标签流式布局的功能,正好一直说给大家讲自定义控件的实现,今天就为大家讲一种android流式布局的实现. 本文原创,转载请注明地址:http://blog.kymjs.com/ 正文 在日常的app使用中,我们会在android 的app中看见热门标签等自动换行的流式布局,今天,我们就来看看如何自定义一个类似热门标签那样的流式布局吧(源码

android流式布局热门标签的实现

在日常的app使用中,我们会在android 的app中看见热门标签等自动换行的流式布局,今天就为大家分享一种android流式布局的实现. 先看最终效果 自定义流式布局的实现 package com.sunny.flowlayout.view; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.util.AttributeSet; import an

Android之自定义流式布局FlowLayout

流式布局常常用于“热门标签”中,大概功能就是将所有的子View一行一行的排列,如果一行中剩下的空间不足以盛放下一个子View,则换到另一行继续排列.这样做的好处是不需要在主线程中自己麻烦定义控件的位置,只需要把生成的控件放到容器中,容器自己会自动排列.首先来看一下运行结果: Android中的自定义容器控件(继承自ViewGroup的控件)都有两个必须实现的方法:onMeasure()和onLayout() (1)onMeasure:测量子View的宽和高,设置自己的宽和高,根据自View的布局

流式布局的实现-1

流式布局可以实现逐行填满的布局效果:适用于关键词搜索和热门展示,可以动态的添加标签,用起来十分方便与快捷 源码下载(由慕课网的老师提供,谢谢) 之后说说主要的安排: 第一篇:创建类,确定继承关系,实现构造函数,确定成员函数: 第二篇:实现FlowLayout(流式布局)主要函数的方法: 第一篇:创建类,确定继承关系,实现构造函数,确定成员函数: 第二篇与之后几篇:实现各函数,并说明成员变量的作用; 和用listView实现下拉刷新一样,还是先分析文件结构: 包括了两个类: public clas

关于静态布局、自适应布局、流式布局、响应式布局、弹性布局的一些概念

一.静态布局(Static Layout)即传统Web设计,网页上的所有元素的尺寸一律使用px作为单位. 1.布局特点:不管浏览器尺寸具体是多少,网页布局始终按照最初写代码时的布局来显示.常规的pc的网站都是静态(定宽度)布局的,也就是设置了min-width,这样的话,如果小于这个宽度就会出现滚动条,如果大于这个宽度则内容居中外加背景,这种设计常见与pc端.2.设计方法: PC:居中布局,所有样式使用绝对宽度/高度(px),设计一个Layout,在屏幕宽高有调整时,使用横向和竖向的滚动条来查阅

移动端布局学习之流式布局1

1.移动端基础 1.1 浏览器现状 国内的UC和QQ 百度等手机浏览器都是根据Webkit修改过来的内核,国内目前尚无自主研发的内核,就像国内的手机系统基本上都是局域安卓修改开发的一样. 意思就是:兼容移动端主流浏览器 处理Webkit内核浏览器即可. 1.2 手机屏幕的现状 移动端设备屏幕尺寸非常多,碎片化严重 Android设备有多种分辨率480*480 480*854 540*960 720*1280 等等 近年来iPhone的碎片化也严重了 其设备的主要分辨率有 640*960 640*

Android自定义之流式布局

流式布局,好处就是父类布局可以自动的判断子孩子是不是需要换行,什么时候需要换行,可以做到网页版的标签的效果.今天就是简单的做了自定义的流式布局. 具体效果: 原理: 其实很简单,Measure  Layout.只需要这两个步骤就可以搞定了.完全的手动去Measure  Layout. 我们看一下代码. 解释就在代码里面做注释了,因为使用为知笔记写的博客,格式不符合代码格式.大家可以看具体的源码.最后又源码下载地址. 1.Measure  测量 @Override protected void o

GUI布局:边界布局、流式布局、网格布局、卡片布局

边界布局 package guiTest; //JFrame默认的是边界布局BorderLayout import java.awt.BorderLayout; import javax.swing.JButton; import javax.swing.JFrame; public class BorderLayoutDemo { public static void main(String[] args) { JFrame f = new JFrame("边界布局BorderLayout&q