Android自定义ViewGroup的实现方法_Android

     在android中提供了常见的几种ViewGroup的实现,包括LinearLayout、Relativeayout、FrameLayout等。这些ViewGroup可以满足我们一般的开发需求,但是对于界面要求复杂的,这几个布局就显得捉襟见肘了。所以自定义的ViewGroup在我们接触过的应用中比比皆是。

     要想实现一个自定义的ViewGroup,第一步是学会自定义属性,这些自定义的属性将让我们配置布局文件的时候更加的灵活。自定义属性是在value目录下声明一个attrs.xml文件。

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="CascadeViewGroup">
  <attr name="verticalspacing" format="dimension"/>
  <attr name="horizontalspacing" format="dimension"/>
 </declare-styleable>

 <declare-styleable name="CascadeViewGroup_LayoutParams">
  <attr name="layout_paddingleft" format="dimension"/>
  <attr name="layout_paddinTop" format="dimension"/>
 </declare-styleable>
</resources>

      在这里我们声明了两个自定义属性集,CascadeViewGroup中的属性是针对我们自定义的CascadeViewGroup组件设置的,也就是可以在布局文件中<CascadeViewGroup>标签中可以使用的属性。另外一个CascadeViewGroup_LayoutParams则是针对于CascadeViewGroup中的子View设置的属性。

    在编写代码前,我们还设置了一个默认的宽度和高度供CascadeLayout使用。这两个属性在dimens.xml定义。

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <dimen name="default_horizontal_spacing">10dp</dimen>
 <dimen name="default_vertical_spacing">10dp</dimen>
</resources>

下面开始编写自定义的组件CascadeLayout了。

package com.app.CustomViewMotion;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by charles on 2015/8/13.
 */
public class CascadeViewGroup extends ViewGroup {

 //自定义布局中设置的宽度和高度
 private int mHoriztonalSpacing;
 private int mVerticalSpacing;

 public CascadeViewGroup(Context context) {
  this(context, null);
 }

 public CascadeViewGroup(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }

 public CascadeViewGroup(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CascadeViewGroup);
  try {
   //获取设置的宽度
   mHoriztonalSpacing = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_horizontalspacing,
     this.getResources().getDimensionPixelSize(R.dimen.default_horizontal_spacing));
   //获取设置的高度
   mVerticalSpacing = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_verticalspacing,
     this.getResources().getDimensionPixelSize(R.dimen.default_vertical_spacing));

  } catch (Exception e) {
   e.printStackTrace();

  } finally {
   a.recycle();
  }
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  final int count = this.getChildCount();
  int width = this.getPaddingLeft();
  int height = this.getPaddingTop();
  for (int i = 0; i < count; i++) {
   final View currentView = this.getChildAt(i);
   this.measureChild(currentView, widthMeasureSpec, heightMeasureSpec);
   CascadeViewGroup.LayoutParams lp = (CascadeViewGroup.LayoutParams) currentView.getLayoutParams();
   if(lp.mSettingPaddingLeft != 0){
    width +=lp.mSettingPaddingLeft;
   }
   if(lp.mSettingPaddingTop != 0){
    height +=lp.mSettingPaddingTop;
   }
   lp.x = width;
   lp.y = height;
   width += mHoriztonalSpacing;
   height += mVerticalSpacing;
  }
  width +=getChildAt(this.getChildCount() - 1).getMeasuredWidth() + this.getPaddingRight();
  height += getChildAt(this.getChildCount() - 1).getMeasuredHeight() + this.getPaddingBottom();
  this.setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));

 }

 @Override
 protected void onLayout(boolean b, int l, int i1, int i2, int i3) {
  final int count = this.getChildCount();
  for (int i = 0; i < count; i++) {
   final View currentView = this.getChildAt(i);
   CascadeViewGroup.LayoutParams lp = (CascadeViewGroup.LayoutParams) currentView.getLayoutParams();
   currentView.layout(lp.x, lp.y, lp.x + currentView.getMeasuredWidth(),
     lp.y + currentView.getMeasuredHeight());
  }

 }

 public static class LayoutParams extends ViewGroup.LayoutParams {
  int x;
  int y;
  int mSettingPaddingLeft;
  int mSettingPaddingTop;

  public LayoutParams(Context c, AttributeSet attrs) {
   super(c, attrs);
   TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.CascadeViewGroup_LayoutParams);
   mSettingPaddingLeft = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_LayoutParams_layout_paddingleft, 0);
   mSettingPaddingTop = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_LayoutParams_layout_paddinTop, 0);
   a.recycle();
  }

  public LayoutParams(int width, int height) {
   super(width, height);
  }

  public LayoutParams(ViewGroup.LayoutParams source) {
   super(source);
  }
 }

 @Override
 protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
  return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
 }

 @Override
 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
  return new LayoutParams(p);
 }

 @Override
 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
  return new LayoutParams(this.getContext(), attrs);
 }
}

代码稍微优点长,但是结构还是很清晰的。

1)构造方法中或者XML文件中配置属性的值。通过TypedArray中的方法获取我们在layout布局中设置的属性,并且将他们保存在成员变量中。

2)构造自定义的内部类LayoutParams。构造这个内部类,可以方便我们在测量我们的子View的时候保存他们的属性值,以便在Layout阶段布局。

3)generateLayoutParams()、generateDefaultParams()等方法。在这些方法中返回我们自定义的layoutParams。至于为什么要重写这些方法,可以查看ViewGroup类的addView()方法就很清楚了。

4)measure阶段。在measure阶段,我们会测量自己的大小,同时也要测量子View的大小,并且将子View的信息保存在LayoutParams中。

5)layout阶段。根据各个子View的信息,布局他们的位置。

最后加上布局文件。

<?xml version="1.0" encoding="utf-8"?>
<!--添加自定义属性给viewGroup-->
<!--新添加的命名空间的后缀必须保持和.xml中声明的包名一致-->
<com.app.CustomViewMotion.CascadeViewGroup
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:ts="http://schemas.android.com/apk/res/com.app.CustomViewMotion"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  ts:horizontalspacing="15dp"
  ts:verticalspacing="15dp">

 <TextView android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:text="text1"
    android:background="#668B8B"/>

 <TextView android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:text="text2"
    android:background="#FFDAB9"/>

 <TextView android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:text="text3"
    android:background="#43CD80"/>

<!--这个子view中添加自定义子view属性-->
 <TextView android:layout_width="100dp"
    android:layout_height="100dp"
    android:gravity="center"
    android:text="text4"
    ts:layout_paddingleft="100dp"
    ts:layout_paddinTop="100dp"
    android:background="#00CED1"/>
</com.app.CustomViewMotion.CascadeViewGroup>

实现的效果如下:

以上就是的全部内容,希望能给大家一个参考,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, viewgroup
自定义
自定义viewgroup实现、自定义viewgroup、安卓自定义viewgroup、自定义滑动viewgroup、自定义viewgroup 刷新,以便于您获取更多的相关知识。

时间: 2024-09-07 10:15:50

Android自定义ViewGroup的实现方法_Android的相关文章

Android自定义dialog简单实现方法_Android

本文实例讲述了Android自定义dialog简单实现方法.分享给大家供大家参考,具体如下: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.function_music); // 实例化新的窗口 Window w = getWindow(); // 获取默认显示数据 Display display

Android自定义ViewGroup实现绚丽的仿支付宝咻一咻雷达脉冲效果_Android

去年春节的时候支付宝推行的集福娃活动着实火的不能再火了,更给力的是春晚又可以全民参与咻一咻集福娃活动,集齐五福就可平分亿元大红包,只可惜没有敬业福--那时候在家没事写了个咻一咻插件,只要到了咻一咻的时间点插件就可以自动的点击咻一咻来咻红包,当时只是纯粹练习这部分技术代码没有公开,后续计划写篇关于插件这方面的文章,扯远了(*^__^*) --我们知道在支付宝的咻一咻页面有个雷达扩散的动画效果,当时感觉动画效果非常棒,于是私下尝试着实现了类似的效果,后来在github发现有大神也写有类似效果,于是读

Android自定义ViewGroup打造各种风格的SlidingMenu_Android

上篇给大家介绍QQ5.0侧滑菜单的视频课程,对于侧滑的时的动画效果的实现有了新的认识,似乎打通了任督二脉,目前可以实现任意效果的侧滑菜单了,感谢鸿洋大大!! 用的是HorizontalScrollView来实现的侧滑菜单功能,HorizontalScrollView的好处是为我们解决了滑动功能,处理了滑动冲突问题,让我们使用起来非常方便,但是滑动和冲突处理都是android中的难点,是我们应该掌握的知识点,掌握了这些,我们可以不依赖于系统的API,随心所欲打造我们想要的效果,因此这篇文章我将直接

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

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

Android自定义ViewGroup打造各种风格的SlidingMenu

上篇给大家介绍QQ5.0侧滑菜单的视频课程,对于侧滑的时的动画效果的实现有了新的认识,似乎打通了任督二脉,目前可以实现任意效果的侧滑菜单了,感谢鸿洋大大!! 用的是HorizontalScrollView来实现的侧滑菜单功能,HorizontalScrollView的好处是为我们解决了滑动功能,处理了滑动冲突问题,让我们使用起来非常方便,但是滑动和冲突处理都是android中的难点,是我们应该掌握的知识点,掌握了这些,我们可以不依赖于系统的API,随心所欲打造我们想要的效果,因此这篇文章我将直接

viewgroup 传参-android自定义ViewGroup的问题

问题描述 android自定义ViewGroup的问题 在名为Demo的activity中用到了一个继承ViewGroup的类MyView来布局,具体是这样的 在Demo的布局文件xml中, 在Demo的代码中 MyView scroll = (MyView) findViewById(R.id.view1); 在MyView中的构造函数 public MyView(Context context, AttributeSet attrs) { //各类操作 } 问题是Demo需要给scroll传

Android自定义dialog简单实现方法

本文实例讲述了Android自定义dialog简单实现方法.分享给大家供大家参考,具体如下: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.function_music); // 实例化新的窗口 Window w = getWindow(); // 获取默认显示数据 Display display

Android自定义ViewGroup实现受边界限制的滚动操作(3)_Android

上一篇文章<自定义viewgroup(2)>地址:http://www.jb51.net/article/100610.htm 代码 package com.example.libingyuan.horizontallistview.ScrollViewGroup; import android.content.Context; import android.util.AttributeSet; import android.util.DisplayMetrics; import androi

Android自定义ViewGroup之WaterfallLayout(二)_Android

上一篇我们学习了自定义ViewGroup的基本步骤,并做了一个CustomGridLayout的实例,这篇我们继续来说说自定义ViewGroup. Android中当有大量照片需要展示的时候,我们可以用GridView作为照片墙,但是GridView太整齐了,有时候不规则也是一种美,瀑布流模型就是这样一个不规则的展示墙,接下来我们尝试用自定义ViewGroup来实现瀑布流. 实现瀑布流的方式也有很多,下面我们一一道来: 一.继承ViewGroup 其实这种实现方式我们只需要在上篇博客的基础上稍作