热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

一、概述:在日常的app使用中,我们会在android的app中看见热门标签等自动换行的流式布局,今天,我们就来看看如何自定

一、概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何

自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出)

类似的自定义布局。下面我们就来详细介绍流式布局的应用特点以及用的的技术点:

1.流式布局的特点以及应用场景

特点:当上面一行的空间不够容纳新的TextView时候,

才开辟下一行的空间

原理图:

9764b990db03853676388fc4bd297835.png

场景:主要用于关键词搜索或者热门标签等场景

2.自定义ViewGroup,重点重写下面两个方法

1、onMeasure:测量子view的宽高,设置自己的宽和高

2、onLayout:设置子view的位置

onMeasure:根据子view的布局文件中属性,来为子view设置测量模式和测量值

测量=测量模式+测量值;

测量模式有3种:

EXACTLY:表示设置了精确的值,一般当childView设置其宽、高为精确值、match_parent时,ViewGroup会将其设置为EXACTLY;

AT_MOST:表示子布局被限制在一个最大值内,一般当childView设置其宽、高为wrap_content时,ViewGroup会将其设置为AT_MOST;

UNSPECIFIED:表示子布局想要多大就多大,一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中;此种模式比较少见。

3.LayoutParams

ViewGroup LayoutParams :每个 ViewGroup 对应一个 LayoutParams; 即 ViewGroup -> LayoutParams

getLayoutParams 不知道转为哪个对应的LayoutParams ,其实很简单,就是如下:

子View.getLayoutParams 得到的LayoutParams对应的就是 子View所在的父控件的LayoutParams;

例如,LinearLayout 里面的子view.getLayoutParams ->LinearLayout.LayoutParams

所以 咱们的FlowLayout 也需要一个LayoutParams,由于上面的效果图是子View的 margin,

所以应该使用MarginLayoutParams。即FlowLayout->MarginLayoutParams

4.最后来看看实现的最终效果图:

c13bad3c464f04a398a4491b76700013.png

二、热门标签的流式布局的实现:

1. 自定义热门标签的ViewGroup实现

根据上面的技术分析,自定义类继承于ViewGroup,并重写 onMeasure和onLayout等方法。具体实现代码如下:

package com.czm.flowlayout;

import java.util.ArrayList;

import java.util.List;

import android.content.Context;

import android.util.AttributeSet;

import android.view.View;

import android.view.ViewGroup;

/**

*

* @author caizhiming

* @created on 2015-4-13

*/

public class XCFlowLayout extends ViewGroup{

//存储所有子View

private List> mAllChildViews &#61; new ArrayList<>();

//每一行的高度

private List mLineHeight &#61; new ArrayList<>();

public XCFlowLayout(Context context) {

this(context, null);

// TODO Auto-generated constructor stub

}

public XCFlowLayout(Context context, AttributeSet attrs) {

this(context, attrs, 0);

// TODO Auto-generated constructor stub

}

public XCFlowLayout(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

// TODO Auto-generated constructor stub

}

&#64;Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// TODO Auto-generated method stub

//父控件传进来的宽度和高度以及对应的测量模式

int sizeWidth &#61; MeasureSpec.getSize(widthMeasureSpec);

int modeWidth &#61; MeasureSpec.getMode(widthMeasureSpec);

int sizeHeight &#61; MeasureSpec.getSize(heightMeasureSpec);

int modeHeight &#61; MeasureSpec.getMode(heightMeasureSpec);

//如果当前ViewGroup的宽高为wrap_content的情况

int width &#61; 0;//自己测量的 宽度

int height &#61; 0;//自己测量的高度

//记录每一行的宽度和高度

int lineWidth &#61; 0;

int lineHeight &#61; 0;

//获取子view的个数

int childCount &#61; getChildCount();

for(int i &#61; 0;i 

View child &#61; getChildAt(i);

//测量子View的宽和高

measureChild(child, widthMeasureSpec, heightMeasureSpec);

//得到LayoutParams

MarginLayoutParams lp &#61; (MarginLayoutParams) getLayoutParams();

//子View占据的宽度

int childWidth &#61; child.getMeasuredWidth() &#43; lp.leftMargin &#43; lp.rightMargin;

//子View占据的高度

int childHeight &#61; child.getMeasuredHeight() &#43; lp.topMargin &#43; lp.bottomMargin;

//换行时候

if(lineWidth &#43; childWidth > sizeWidth){

//对比得到最大的宽度

width &#61; Math.max(width, lineWidth);

//重置lineWidth

lineWidth &#61; childWidth;

//记录行高

height &#43;&#61; lineHeight;

lineHeight &#61; childHeight;

}else{//不换行情况

//叠加行宽

lineWidth &#43;&#61; childWidth;

//得到最大行高

lineHeight &#61; Math.max(lineHeight, childHeight);

}

//处理最后一个子View的情况

if(i &#61;&#61; childCount -1){

width &#61; Math.max(width, lineWidth);

height &#43;&#61; lineHeight;

}

}

//wrap_content

setMeasuredDimension(modeWidth &#61;&#61; MeasureSpec.EXACTLY ? sizeWidth : width,

modeHeight &#61;&#61; MeasureSpec.EXACTLY ? sizeHeight : height);

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

&#64;Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

// TODO Auto-generated method stub

mAllChildViews.clear();

mLineHeight.clear();

//获取当前ViewGroup的宽度

int width &#61; getWidth();

int lineWidth &#61; 0;

int lineHeight &#61; 0;

//记录当前行的view

List lineViews &#61; new ArrayList();

int childCount &#61; getChildCount();

for(int i &#61; 0;i 

View child &#61; getChildAt(i);

MarginLayoutParams lp &#61; (MarginLayoutParams) child.getLayoutParams();

int childWidth &#61; child.getMeasuredWidth();

int childHeight &#61; child.getMeasuredHeight();

//如果需要换行

if(childWidth &#43; lineWidth &#43; lp.leftMargin &#43; lp.rightMargin > width){

//记录LineHeight

mLineHeight.add(lineHeight);

//记录当前行的Views

mAllChildViews.add(lineViews);

//重置行的宽高

lineWidth &#61; 0;

lineHeight &#61; childHeight &#43; lp.topMargin &#43; lp.bottomMargin;

//重置view的集合

lineViews &#61; new ArrayList();

}

lineWidth &#43;&#61; childWidth &#43; lp.leftMargin &#43; lp.rightMargin;

lineHeight &#61; Math.max(lineHeight, childHeight &#43; lp.topMargin &#43; lp.bottomMargin);

lineViews.add(child);

}

//处理最后一行

mLineHeight.add(lineHeight);

mAllChildViews.add(lineViews);

//设置子View的位置

int left &#61; 0;

int top &#61; 0;

//获取行数

int lineCount &#61; mAllChildViews.size();

for(int i &#61; 0; i 

//当前行的views和高度

lineViews &#61; mAllChildViews.get(i);

lineHeight &#61; mLineHeight.get(i);

for(int j &#61; 0; j 

View child &#61; lineViews.get(j);

//判断是否显示

if(child.getVisibility() &#61;&#61; View.GONE){

continue;

}

MarginLayoutParams lp &#61; (MarginLayoutParams) child.getLayoutParams();

int cLeft &#61; left &#43; lp.leftMargin;

int cTop &#61; top &#43; lp.topMargin;

int cRight &#61; cLeft &#43; child.getMeasuredWidth();

int cBottom &#61; cTop &#43; child.getMeasuredHeight();

//进行子View进行布局

child.layout(cLeft, cTop, cRight, cBottom);

left &#43;&#61; child.getMeasuredWidth() &#43; lp.leftMargin &#43; lp.rightMargin;

}

left &#61; 0;

top &#43;&#61; lineHeight;

}

}

/**

* 与当前ViewGroup对应的LayoutParams

*/

&#64;Override

public LayoutParams generateLayoutParams(AttributeSet attrs) {

// TODO Auto-generated method stub

return new MarginLayoutParams(getContext(), attrs);

}

}

2.相关的布局文件&#xff1a;

引用自定义控件&#xff1a;

xmlns:tools&#61;"http://schemas.android.com/tools"

android:id&#61;"&#64;&#43;id/container"

android:layout_width&#61;"match_parent"

android:layout_height&#61;"match_parent" >

android:id&#61;"&#64;&#43;id/flowlayout"

android:layout_width&#61;"match_parent"

android:layout_height&#61;"match_parent" >

TextView的样式文件&#xff1a;

android:left&#61;"5dp"

android:right&#61;"5dp"

android:top&#61;"5dp"

android:bottom&#61;"5dp"

/>

三、使用该自定义布局控件类

最后&#xff0c;如何使用该自定义的热门标签控件类呢&#xff1f;很简单&#xff0c;请看下面实例代码&#xff1a;

package com.czm.flowlayout;

import android.app.Activity;

import android.graphics.Color;

import android.os.Bundle;

import android.view.ViewGroup.LayoutParams;

import android.view.ViewGroup.MarginLayoutParams;

import android.widget.TextView;

/**

*

* &#64;author caizhiming

* &#64;created on 2015-4-13

*/

public class MainActivity extends Activity {

private String mNames[] &#61; {

"welcome","android","TextView",

"apple","jamy","kobe bryant",

"jordan","layout","viewgroup",

"margin","padding","text",

"name","type","search","logcat"

};

private XCFlowLayout mFlowLayout;

&#64;Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initChildViews();

}

private void initChildViews() {

// TODO Auto-generated method stub

mFlowLayout &#61; (XCFlowLayout) findViewById(R.id.flowlayout);

MarginLayoutParams lp &#61; new MarginLayoutParams(

LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);

lp.leftMargin &#61; 5;

lp.rightMargin &#61; 5;

lp.topMargin &#61; 5;

lp.bottomMargin &#61; 5;

for(int i &#61; 0; i 

TextView view &#61; new TextView(this);

view.setText(mNames[i]);

view.setTextColor(Color.WHITE);

view.setBackgroundDrawable(getResources().getDrawable(R.drawable.textview_bg));

mFlowLayout.addView(view,lp);

}

}

}

四、源码下载

此源码下载完之后&#xff0c;往往有个要点我们容易忽略&#xff0c;那就是源码的安全性问题&#xff0c;此处可点击移动应用安全智能服务提供商爱加密的Android加密&#xff0c;源码保护&#xff01;



推荐阅读
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 使用圣杯布局模式实现网站首页的内容布局
    本文介绍了使用圣杯布局模式实现网站首页的内容布局的方法,包括HTML部分代码和实例。同时还提供了公司新闻、最新产品、关于我们、联系我们等页面的布局示例。商品展示区包括了车里子和农家生态土鸡蛋等产品的价格信息。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 本文介绍了如何在Jquery中通过元素的样式值获取元素,并将其赋值给一个变量。提供了5种解决方案供参考。 ... [详细]
  • Java图形化计算器设计与实现
    本文介绍了使用Java编程语言设计和实现图形化计算器的方法。通过使用swing包和awt包中的组件,作者创建了一个具有按钮监听器和自定义界面尺寸和布局的计算器。文章还分享了在图形化界面设计中的一些心得体会。 ... [详细]
  • 今天就跟大家聊聊有关怎么在Android应用中实现一个换肤功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根 ... [详细]
  • android 触屏处理流程,android触摸事件处理流程 ? FOOKWOOD「建议收藏」
    android触屏处理流程,android触摸事件处理流程?FOOKWOOD「建议收藏」最近在工作中,经常需要处理触摸事件,但是有时候会出现一些奇怪的bug,比如有时候会检测不到A ... [详细]
  • SmartRefreshLayout自定义头部刷新和底部加载
    1.添加依赖implementation‘com.scwang.smartrefresh:SmartRefreshLayout:1.0.3’implementation‘com.s ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
author-avatar
迷失港湾的豪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有