Android自定义控件ViewGroup实现标签云

本文实例为大家分享了Android自定义控件ViewGroup实现标签云的具体代码,供大家参考,具体内容如下

实现的功能:

基本绘制流程:

构造函数获取自定义属性
onMeasure()方法,测量子控件的大小
onLayout()方法,对子控件进行布局

1、自定义属性

<resources>

  <declare-styleable name="TabsViewGroup">
    <attr name="tabVerticalSpace" format="dimension" />
    <attr name="tabHorizontalSpace" format="dimension" />
  </declare-styleable>

</resources>

2、构造函数中获取自定义属性值

public TabsViewGroup(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray attrArray = context.obtainStyledAttributes(attrs, R.styleable.TabsViewGroup);
    if (attrArray != null) {
      childHorizontalSpace = attrArray.getDimensionPixelSize(R.styleable.TabsViewGroup_tabHorizontalSpace, 0);
      childVerticalSpace = attrArray.getDimensionPixelSize(R.styleable.TabsViewGroup_tabHorizontalSpace, 0);
      attrArray.recycle();
    }
  }

3、onMeasure函数测量子控件大小,然后设置当前控件大小

 @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int widthModel = MeasureSpec.getMode(widthMeasureSpec);
    int heightModel = MeasureSpec.getMode(heightMeasureSpec);

    //输出宽度高度以及测量模式
    Log.i(TAG, "sizeWidth :" + widthSize);
    switch (widthModel) {
      case MeasureSpec.AT_MOST:
        Log.i(TAG, "Width model AT_MOST");
        break;
      case MeasureSpec.EXACTLY:
        Log.i(TAG, "Width model EXACTLY");
        break;
      case MeasureSpec.UNSPECIFIED:
        Log.i(TAG, "Width model UNSPECIFIED");
        break;
    }

    Log.i(TAG, "sizeHeight :" + heightSize);
    switch (heightModel) {
      case MeasureSpec.AT_MOST:
        Log.i(TAG, "Height model AT_MOST");
        break;
      case MeasureSpec.EXACTLY:
        Log.i(TAG, "Height model EXACTLY");
        break;
      case MeasureSpec.UNSPECIFIED:
        Log.i(TAG, "Height model UNSPECIFIED");
        break;
    }
    //左右边距
    int left = getPaddingLeft();
    int top = getPaddingTop();
    //记录每一行的宽度和高度
    int lineWidth = 0;
    int lineHeight = 0;
    // 如果是warp_content情况下,记录宽和高
    int containerWidth = 0;
    int containerHeight = 0;
    // 遍历每个子元素
    for (int index = 0; index < getChildCount(); index++) {
      View child = getChildAt(index);
      if (child.getVisibility() == GONE) {
        continue;
      }
      measureChild(child, widthMeasureSpec, heightMeasureSpec);
      MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();

      int childWidth = child.getMeasuredWidth() + params.leftMargin + params.rightMargin + childHorizontalSpace;
      int childHeight = child.getMeasuredHeight() + params.topMargin + params.bottomMargin + childVerticalSpace;

      if (lineWidth + childWidth > widthSize - getPaddingRight() - getPaddingLeft()) {
        containerWidth = Math.max(lineWidth, childWidth);
        lineWidth = childWidth;
        containerHeight += lineHeight;
        lineHeight = childHeight;
        Rect rect = new Rect(left,
            containerHeight + top,
            left + childWidth - childHorizontalSpace,
            containerHeight + top + child.getMeasuredHeight());
        child.setTag(rect);
      } else {
        Rect rect = new Rect(lineWidth + left,
            containerHeight + top,
            lineWidth + left + childWidth - childHorizontalSpace,
            containerHeight + top + child.getMeasuredHeight());
        child.setTag(rect);
        lineWidth += childWidth;
        lineHeight = Math.max(lineHeight, childHeight);
      }
    }

    containerWidth = Math.max(containerWidth, lineWidth) + getPaddingLeft() + getPaddingRight();
    containerHeight += lineHeight + getPaddingTop() + getPaddingBottom();
    containerHeight -= childVerticalSpace;
    setMeasuredDimension(widthModel == MeasureSpec.EXACTLY ? widthSize : containerWidth,
        heightModel == MeasureSpec.EXACTLY ? heightSize : containerHeight);
}

4、onLayout函数对所有子控件重新布局

@Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
      View child = getChildAt(i);
      if (child.getVisibility() == GONE) {
        continue;
      }
      Rect location = (Rect) child.getTag();
      child.layout(location.left, location.top, location.right, location.bottom);
    }
}

使用方法

1、布局问自己中直接引用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:owen="http://schemas.android.com/apk/res-auto"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#ffffff"
  android:orientation="vertical">

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:textSize="16sp"
    android:text="国际足球"/>

  <View
    android:layout_width="wrap_content"
    android:layout_height="0.1dp"
    android:background="#e0e0e0"/>

  <com.ownchan.tabviewgroup.view.TabsViewGroup
    android:id="@+id/tabs_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dip"
    owen:tabHorizontalSpace="10dp"
    owen:tabVerticalSpace="10dp" />

</LinearLayout>

2、代码添加标签

@Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();
  }

  private void initView() {
    TabsViewGroup tabsViewGroup = (TabsViewGroup) findViewById(R.id.tabs_view);
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
        ViewGroup.LayoutParams.WRAP_CONTENT);
    String[] tabs = new String[]{"世预赛欧洲区",
        "世预赛南美区", "五人世界杯", "意甲", "美国大联盟", "乌超", "英冠", "国际冠军杯", "巴西圣保罗州杯", "巴西杯"};
    for (int i = 0; i < tabs.length; i++) {
      TextView textView = new TextView(this);
      textView.setText(tabs[i]);
      textView.setTextColor(Color.WHITE);
      textView.setBackgroundDrawable(getResources().getDrawable(R.drawable.tabs_bg));
      textView.setGravity(Gravity.CENTER);
      textView.setPadding(10, 0, 10, 0);
      textView.setTextSize(16);
      tabsViewGroup.addView(textView, params);
    }
}

效果图:

项目Github地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android实现3D标签云简单效果

    本文实例为大家分享了Android实现3D标签云效果展示的具体代码,供大家参考,具体内容如下 一.关于3D标签云 TagCloudView是一个完全基于Android ViewGroup编写的控件,支持将一组View展示为一个3D标签云,并支持全方向滚动. GitHub中的链接地址 (一)效果 页面上标签的数据可以自己定义,数据页面可以滑动选择. (二)AndroidStudio中使用 1.在build.gradle中添加 compile 'com.moxun:tagcloudlib:1.0.3

  • Android实现3D云标签效果

    本文实例为大家分享了Android实现3D云标签效果的具体代码,供大家参考,具体内容如下 一.自定义View public class TagCloudView extends RelativeLayout { RelativeLayout navigation_bar; TextView mTextView1; private final float TOUCH_SCALE_FACTOR = .8f; private float tspeed; private TagCloud mTagClo

  • Android实现随机圆形云标签效果

    本文实例为大家分享了Android实现圆形云标签效果展示的具体代码,供大家参考,具体内容如下 下面是实现的效果图: 这个适合用于选择 用户的一些兴趣标签,个性名片等. 代码: Activity package com.dyl.cloudtags; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; import android.app.Activity; import android.cont

  • android LabelView实现标签云效果

    今天我们来做一个android上的标签云效果, 虽然还不是很完美,但是已经足够可以展现标签云的效果了,首先来看看效果吧. 额,录屏只能录到这个份上了,凑活着看吧.今天我们就来实现一下这个效果, 这次我选择直接继承view来, 什么? 这样的效果不是SurfaceView擅长的吗? 为什么要view,其实都可以了, 我选择view,是因为:额,我对SurfaceView还不是很熟悉. 废话少说, 下面开始上代码 public class LabelView extends View { priva

  • Android TagCloudView云标签的使用方法

    这两天做了一个项目,发现标签不能更改任意一个标签的字体的颜色,需求如同置前标签,然后就对tagcloudeview稍做修改做了这么一个demo.不为别的,只为以后自己用的时候方便拷贝. 先看效果图: 这两天做了一个项目,需求如同置前标签,然后就对tagcloudeview稍做修改做了这么一个demo.不为别的,只为以后自己用的时候方便拷贝. 云标签开源地址 在源码里面加了两个方法 /**修改某些位置定点颜色**/ public void setTagsByPosition(HashMap<Int

  • Android实现3D标签云效果

    最近业务需求,要求实现一个3D星球环绕效果,经过百般查找,终于找到了这个功能. 来先看看效果图: 首先还是添加第三方依赖库: compile 'com.moxun:tagcloudlib:1.1.0' 布局: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.an

  • Android自定义控件ViewGroup实现标签云(四)

    前言: 前面几篇讲了自定义控件绘制原理Android自定义控件基本原理详解(一) ,Android自定义控件之自定义属性(二) ,Android自定义控件之自定义组合控件(三),常言道:"好记性不如烂笔头,光说不练假把式!!!",作为一名学渣就是因为没有遵循这句名言才沦落于此,所以要谨遵教诲,注重理论与实践相结合,今天通过自定义ViewGroup来实现一下项目中用到的标签云. 需求背景: 公司需要实现一个知识点的标签显示,每个标签的长度未知,如下图所示 基本绘制流程: 绘制原理这里不再

  • android随机生成圆形云标签效果

    这个适合用于选择 用户的一些兴趣标签,个性名片等. package com.dyl.cloudtags; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; import android.view.Vi

  • Android自定义控件ViewGroup实现标签云

    本文实例为大家分享了Android自定义控件ViewGroup实现标签云的具体代码,供大家参考,具体内容如下 实现的功能: 基本绘制流程: 构造函数获取自定义属性 onMeasure()方法,测量子控件的大小 onLayout()方法,对子控件进行布局 1.自定义属性 <resources> <declare-styleable name="TabsViewGroup"> <attr name="tabVerticalSpace" fo

  • Android自定义ViewGroup实现标签流效果

    本文实例为大家分享了Android自定义ViewGroup实现标签流效果的具体代码,供大家参考,具体内容如下 自定义View,一是为了满足设计需求,二是开发者进阶的标志之一.随心所欲就是我等奋斗的目标!!! 效果 实现逻辑 明确需求 1.标签流效果;2.可以动态添加标签;3.标签需要有点击效果以及回调; 整理思路 既然要装载标签,就需要自定义ViewGroup ,而自定义ViewGroup 比较复杂的就是onLayout()中对子View的排版.既然是标签,在一行中一定要显示完整,在排版的时候注

  • Android自定义ViewGroup实现标签流容器FlowLayout

    本篇文章讲的是Android 自定义ViewGroup之实现标签流式布局-FlowLayout,开发中我们会经常需要实现类似于热门标签等自动换行的流式布局的功能,网上也有很多这样的FlowLayout,但不影响我对其的学习.和往常一样,主要还是想总结一下自定义ViewGroup的开发过程以及一些需要注意的地方. 按照惯例,我们先来看看效果图 一.写代码之前,有几个是问题是我们先要弄清楚的: 1.什么是ViewGroup:从名字上来看,它可以被翻译为控件组,言外之意是ViewGroup内部包含了许

  • Android自定义ViewGroup实现标签浮动效果

    前面在学习鸿洋大神的一些自定义的View文章,看到了自定义ViewGroup实现浮动标签,初步看了下他的思路以及结合自己的思路完成了自己的浮动标签的自定义ViewGroup.目前实现的可以动态添加标签.可点击.效果图如下: 1.思路  首先在onMeasure方法中测量ViewGroup的宽和高,重点是处理当我们自定义的ViewGroup设置为wrap_content的情况下,如何去测量其大小的问题.当我们自定义的ViewGroup设置为wrap_content时,我们需要让子View先去测量自

  • Android自定义控件实现底部菜单(下)

    在app中经常会用到底部菜单的控件,每次都需要写好多代码,今天我们用到了前几篇博客里的控件来进一步封装底部菜单.先看效果图: 主要包括以下功能: 1 设置icon以及点击之后的icon 2 设置文字 3 设置文字颜色以及点击之后的文字颜色 4 设置未读数量.更多以及new 我们先看如何使用,然后再看如何实现的 1 在布局文件中引用MenuM <com.landptf.view.MenuM android:id="@+id/mm_bottom" android:layout_wid

  • Android自定义控件案例汇总1(菜单、popupwindow、viewpager)

    自定义控件是根据自己的需要自己来编写控件.安卓自带的控件有时候无法满足你的需求,这种时候,我们只能去自己去实现适合项目的控件.同时,安卓也允许你去继承已经存在的控件或者实现你自己的控件以便优化界面和创造更加丰富的用户体验.在平常的项目中,我们 人为的把自定义控件分为两种:一种是组合方式实现.一种是通过继承view或viewgroup及其子类实现.两者都可以实现我们想要的效果,因此,我们可以根据自己的需求,选择合适的方案.本文以案例的形式来显示几种较为常见的自定义控件. 案例一 优酷菜单: 功能介

随机推荐