Android自定義ViewGroup的實(shí)現(xiàn)方法
在android中提供了常見(jiàn)的幾種ViewGroup的實(shí)現(xiàn),包括LinearLayout、Relativeayout、FrameLayout等。這些ViewGroup可以滿足我們一般的開發(fā)需求,但是對(duì)于界面要求復(fù)雜的,這幾個(gè)布局就顯得捉襟見(jiàn)肘了。所以自定義的ViewGroup在我們接觸過(guò)的應(yīng)用中比比皆是。
要想實(shí)現(xiàn)一個(gè)自定義的ViewGroup,第一步是學(xué)會(huì)自定義屬性,這些自定義的屬性將讓我們配置布局文件的時(shí)候更加的靈活。自定義屬性是在value目錄下聲明一個(gè)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>
在這里我們聲明了兩個(gè)自定義屬性集,CascadeViewGroup中的屬性是針對(duì)我們自定義的CascadeViewGroup組件設(shè)置的,也就是可以在布局文件中<CascadeViewGroup>標(biāo)簽中可以使用的屬性。另外一個(gè)CascadeViewGroup_LayoutParams則是針對(duì)于CascadeViewGroup中的子View設(shè)置的屬性。
在編寫代碼前,我們還設(shè)置了一個(gè)默認(rèn)的寬度和高度供CascadeLayout使用。這兩個(gè)屬性在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 {
//自定義布局中設(shè)置的寬度和高度
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 {
//獲取設(shè)置的寬度
mHoriztonalSpacing = a.getDimensionPixelSize(R.styleable.CascadeViewGroup_horizontalspacing,
this.getResources().getDimensionPixelSize(R.dimen.default_horizontal_spacing));
//獲取設(shè)置的高度
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);
}
}
代碼稍微優(yōu)點(diǎn)長(zhǎng),但是結(jié)構(gòu)還是很清晰的。
1)構(gòu)造方法中或者XML文件中配置屬性的值。通過(guò)TypedArray中的方法獲取我們?cè)趌ayout布局中設(shè)置的屬性,并且將他們保存在成員變量中。
2)構(gòu)造自定義的內(nèi)部類LayoutParams。構(gòu)造這個(gè)內(nèi)部類,可以方便我們?cè)跍y(cè)量我們的子View的時(shí)候保存他們的屬性值,以便在Layout階段布局。
3)generateLayoutParams()、generateDefaultParams()等方法。在這些方法中返回我們自定義的layoutParams。至于為什么要重寫這些方法,可以查看ViewGroup類的addView()方法就很清楚了。
4)measure階段。在measure階段,我們會(huì)測(cè)量自己的大小,同時(shí)也要測(cè)量子View的大小,并且將子View的信息保存在LayoutParams中。
5)layout階段。根據(jù)各個(gè)子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"/>
<!--這個(gè)子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>
實(shí)現(xiàn)的效果如下:

以上就是的全部?jī)?nèi)容,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Android自定義ViewGroup實(shí)現(xiàn)帶箭頭的圓角矩形菜單
- Android自定義ViewGroup實(shí)現(xiàn)堆疊頭像的點(diǎn)贊Layout
- Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽浮動(dòng)效果
- Android自定義ViewGroup之實(shí)現(xiàn)FlowLayout流式布局
- Android App開發(fā)中自定義View和ViewGroup的實(shí)例教程
- 一篇文章弄懂Android自定義viewgroup的相關(guān)難點(diǎn)
- Android應(yīng)用開發(fā)中自定義ViewGroup的究極攻略
- Android自定義ViewGroup實(shí)現(xiàn)受邊界限制的滾動(dòng)操作(3)
- Android動(dòng)畫效果之自定義ViewGroup添加布局動(dòng)畫(五)
- Android自定義ViewGroup實(shí)現(xiàn)朋友圈九宮格控件
相關(guān)文章
Android百度地圖添加Marker失真問(wèn)題的解決方案
本篇文章主要介紹了Android百度地圖添加Marker失真問(wèn)題的解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
Android?獲取實(shí)時(shí)網(wǎng)速實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了Android?獲取實(shí)時(shí)網(wǎng)速實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Android中實(shí)現(xiàn)iOS中的毛玻璃效果
為了實(shí)現(xiàn)毛玻璃效果,我們需要一組compute kernels(.rs文件中編寫),及一組用于控制renderScript相關(guān)的Javaapi(.rs文件自動(dòng)生成為Java類)。 這篇文章主要介紹了Android中實(shí)現(xiàn)iOS中的毛玻璃效果,需要的朋友可以參考下2017-06-06
android實(shí)現(xiàn)Uri獲取真實(shí)路徑轉(zhuǎn)換成File的方法
這篇文章主要介紹了android實(shí)現(xiàn)Uri獲取真實(shí)路徑轉(zhuǎn)換成File的方法,涉及Android操作路徑的相關(guān)技巧,需要的朋友可以參考下2015-05-05
Android Studio屏幕方向以及UI界面狀態(tài)的保存代碼詳解
在本篇文章里小編給各位整理的是關(guān)于Android Studio屏幕方向以及UI界面狀態(tài)的保存代碼以及相關(guān)知識(shí)點(diǎn),需要的跟著學(xué)習(xí)下。2019-10-10
Android實(shí)現(xiàn)藍(lán)牙串口通訊
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)藍(lán)牙串口通訊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
Android檢查手機(jī)網(wǎng)絡(luò)狀態(tài)及網(wǎng)絡(luò)類型的方法
這篇文章主要介紹了Android檢查手機(jī)網(wǎng)絡(luò)狀態(tài)及網(wǎng)絡(luò)類型的方法,涉及Android檢測(cè)手機(jī)網(wǎng)絡(luò)狀態(tài)的技巧,需要的朋友可以參考下2015-04-04
Android 自定義閃屏頁(yè)廣告倒計(jì)時(shí)view效果
這篇文章主要介紹了Android 自定義閃屏頁(yè)廣告倒計(jì)時(shí)view效果,需要的朋友可以參考下2017-05-05
Android開發(fā)實(shí)現(xiàn)圓形圖片功能示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)圓形圖片功能,涉及Android實(shí)現(xiàn)圓形圖片的界面布局與CirImageView組件相關(guān)使用操作技巧,需要的朋友可以參考下2019-04-04

