Android View嵌套和事件传递手稿
2015-12-22 16:36
573 查看
只所以写这样一个专题手稿,是平时在群里很多群友经常问到当动态添加View,形成嵌套View,视觉效果做出来了,但是事件如何传递了呢,特别是View有层叠的效果,那么事件又如何传递和处理,以及View如何在视窗中如何移动处理.
所以大致写一个专题手稿大致介绍一下,还望不足之处希望不吝指正和批评,非常感谢.
工程下载链接:http://pan.baidu.com/s/1i3M6ntj
首先的思路如下:
我先做一个实现如上图所示的View嵌套层级的一个android 工程,步骤如下:
由于我每一次手稿专题都会用到一个行动代号,这里的代号是 : Durian
<1> : 新建一个android工程如下:
<2> : 代码如下:
/**
* @Title: DurianSubFrameLayout.java
* @Package com.durian.view
* @Description: TODO
* @author zhibao.liu from durian organization
* @date 2015-12-22 下午02:47:13
* @version V1.0
*/
package com.durian.viewgroup;
import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Window;
import android.widget.Toast;
/**
* @ClassName: DurianSubFrameLayout
* @Description: TODO
* @author zhibao.liu Freelancer
* @email warden_sprite@foxmail.com
* @date 2015-12-22 下午02:47:13
*
*/
public class DurianMainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.durian_main);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
Toast.makeText(DurianMainActivity.this,
"heigth : " + dm.heightPixels + "width : " + dm.widthPixels,
Toast.LENGTH_SHORT).show();
//1824 1200
}
}
这里面我运行的机器是Nexus 平板,而且重要在是屏幕的大小尺寸,所以下面设置尺寸都是随手设置的.
上面是顶层容器继承ViewGroup的.
Activity的布局文件如下:
程序中涉及到的View的背景:alhpa_background.xml
layout_backgrond.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid
android:color="#ffffffff"/>
<stroke
android:width="2dip"
android:color="#ff00ff"/>
</shape>
其他的基本上都还好, 运行程序如下:
做出上面的程序,主要涉及到两个需要实现的方法:
每一个 View在构建时,都会执行onLayout(...)这个方法,在这个方法里面,通过:
可以获得这个容器中所有子View的对象,并且通过view.layout重新确定在这个容器中的位置,同时需要注意,view.layout(....)四个参数是相对直接父容器而言的,即相对的,和android显示屏幕的尺寸有关系,但是没有直接的关系.
至于onMeasure(...)这个方式,在我的程序里面直接设置参量进去了,但是实际上面需要做一下变换:
一般情况可以如下:
获得到的specSize_Width和specSize_Height的尺寸实际仍然需要参考上一层父容器中onlayout中指定的尺寸大小,最终能够显示在屏幕,最终是由父容器中的Onlayout中分配的尺寸大小决定的.
既然上面给出了那么层级的按钮,可想而知,是用来处理事件的,下一篇继续.
代码参考:
android系统源代码 :
View.java,以及ViewRoot.java等部分.
所以大致写一个专题手稿大致介绍一下,还望不足之处希望不吝指正和批评,非常感谢.
工程下载链接:http://pan.baidu.com/s/1i3M6ntj
首先的思路如下:
我先做一个实现如上图所示的View嵌套层级的一个android 工程,步骤如下:
由于我每一次手稿专题都会用到一个行动代号,这里的代号是 : Durian
<1> : 新建一个android工程如下:
<2> : 代码如下:
/**
* @Title: DurianSubFrameLayout.java
* @Package com.durian.view
* @Description: TODO
* @author zhibao.liu from durian organization
* @date 2015-12-22 下午02:47:13
* @version V1.0
*/
package com.durian.viewgroup;
import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Window;
import android.widget.Toast;
/**
* @ClassName: DurianSubFrameLayout
* @Description: TODO
* @author zhibao.liu Freelancer
* @email warden_sprite@foxmail.com
* @date 2015-12-22 下午02:47:13
*
*/
public class DurianMainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.durian_main);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
Toast.makeText(DurianMainActivity.this,
"heigth : " + dm.heightPixels + "width : " + dm.widthPixels,
Toast.LENGTH_SHORT).show();
//1824 1200
}
}
这里面我运行的机器是Nexus 平板,而且重要在是屏幕的大小尺寸,所以下面设置尺寸都是随手设置的.
/** * @Title: DurianViewGroup.java * @Package com.durian.view * @Description: TODO * @author zhibao.liu from durian organization * @date 2015-12-21 下午04:06:28 * @version V1.0 */ package com.durian.view; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Button; public class DurianViewGroup extends ViewGroup { private final static String TAG = "DurianViewGroup"; private DurianLinearLayout mDurianLinearLayout; private DurianFrameLayout mDurianFrameLayout; private int mDisplayWidth = 1200; private int mDisplayHeight = 1824; private Button mButton; public DurianViewGroup(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub initView(context); } public DurianViewGroup(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub initView(context); } public DurianViewGroup(Context context) { super(context); // TODO Auto-generated constructor stub initView(context); } private void initView(Context context) { Log.i(TAG, "mDisplayWidth : " + mDisplayWidth + " mDisplayHeight : " + mDisplayHeight); mDurianFrameLayout = new DurianFrameLayout(context); addView(mDurianFrameLayout); mButton = new Button(context); mButton.setText("Top Button"); addView(mButton); setBackgroundColor(Color.BLUE); } /* * (non-Javadoc) * * @see android.view.ViewGroup#onLayout(boolean, int, int, int, int) */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub for (int i = 0; i < getChildCount(); i++) { Log.i(TAG, "child : " + i); View child = getChildAt(i); if (child instanceof Button) { child.layout(mDisplayWidth / 2 - 250, mDisplayHeight / 2 + 500, mDisplayWidth / 2 + 250, mDisplayHeight / 2 + 750); } else { child.layout(0, 0, mDisplayWidth, mDisplayHeight / 2 + 500); } } } @Override public boolean dispatchKeyEvent(KeyEvent event) { // TODO Auto-generated method stub return super.dispatchKeyEvent(event); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mDisplayWidth, mDisplayHeight); } }
上面是顶层容器继承ViewGroup的.
/** * @Title: DurianFrameLayout.java * @Package com.durian.view * @Description: TODO * @author zhibao.liu from durian organization * @date 2015-12-22 上午09:17:11 * @version V1.0 */ package com.durian.view; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; public class DurianFrameLayout extends FrameLayout { private final static String TAG = "DurianFrameLayout"; private DurianLinearLayout mDurianLinearLayout; private DurianSubFrameLayout mDurianSubFrameLayout; private int mDisplayWidth = 1200; private int mDisplayHeight = 1824; private Button mButton; public DurianFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub initView(context); } public DurianFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub initView(context); } public DurianFrameLayout(Context context) { super(context); // TODO Auto-generated constructor stub initView(context); } private void initView(Context context) { mDurianLinearLayout = new DurianLinearLayout(context); addView(mDurianLinearLayout); mDurianSubFrameLayout = new DurianSubFrameLayout(context); addView(mDurianSubFrameLayout); mButton = new Button(context); mButton.setText("Zero FrameLayout Button"); addView(mButton); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // TODO Auto-generated method stub super.onLayout(changed, left, top, right, bottom); for (int i = 0; i < getChildCount(); i++) { Log.i(TAG, "*** count i : " + i); View child = getChildAt(i); if (child instanceof Button) { child.layout(mDisplayWidth/2-250, (i + 0) * mDisplayHeight / 4, mDisplayWidth/2+250, (i + 1) * mDisplayHeight / 4); } else { child.layout(0, i * (mDisplayHeight / 4), mDisplayWidth, (i + 1) * mDisplayHeight / 4); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mDisplayWidth, mDisplayHeight / 2+500); } }
/** * @Title: DurianLinearLayout.java * @Package com.durian.view * @Description: TODO * @author zhibao.liu from durian organization * @date 2015-12-21 下午05:27:56 * @version V1.0 */ package com.durian.view; import android.content.Context; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; import android.widget.LinearLayout; import com.durian.viewgroup.R; public class DurianLinearLayout extends LinearLayout { private final static String TAG = "DurianLinearLayout"; private Button mLinearButton; private int mDisplayWidth = 1200; private int mDisplayHeight = 1824; public DurianLinearLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public DurianLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public DurianLinearLayout(Context context) { super(context); // TODO Auto-generated constructor stub initView(context); } private void initView(Context context) { Log.i(TAG, "mDisplayWidth : " + mDisplayWidth + " mDisplayHeight : " + mDisplayHeight); mLinearButton = new Button(context); mLinearButton.setText("First Linear Button"); addView(mLinearButton); setBackgroundDrawable(context.getResources().getDrawable( R.drawable.layout_backgroud)); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub super.onLayout(changed, l, t, r, b); for (int i = 0; i < getChildCount(); i++) { Log.i(TAG, "*** count i : " + i); View child = getChildAt(i); child.layout(mDisplayWidth / 2 - 200, 0, mDisplayWidth / 2 + 200, 120); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mDisplayWidth, mDisplayHeight / 2); } }
/** * @Title: DurianSubFrameLayout.java * @Package com.durian.view * @Description: TODO * @author zhibao.liu from durian organization * @date 2015-12-22 下午02:47:13 * @version V1.0 */ package com.durian.view; import com.durian.viewgroup.R; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; /** * @ClassName: DurianSubFrameLayout * @Description: TODO * @author zhibao.liu Freelancer * @email warden_sprite@foxmail.com * @date 2015-12-22 下午02:47:13 * */ public class DurianSubFrameLayout extends FrameLayout { private final static String TAG="DurianSubFrameLayout"; private int mDisplayWidth=1200; private int mDisplayHeight=1824; private Button mButton; private DurianSubLinearLayout mDurianSubLinearLayout; public DurianSubFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub initView(context); } public DurianSubFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub initView(context); } public DurianSubFrameLayout(Context context) { super(context); // TODO Auto-generated constructor stub initView(context); } private void initView(Context context){ mButton=new Button(context); mButton.setText("Second SubFrameLayout Button"); addView(mButton); mDurianSubLinearLayout=new DurianSubLinearLayout(context); addView(mDurianSubLinearLayout); setBackgroundDrawable(context.getResources().getDrawable( R.drawable.alpha_background)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // TODO Auto-generated method stub super.onLayout(changed, left, top, right, bottom); for (int i = 0; i < getChildCount(); i++) { Log.i(TAG, "*** count i : " + i); View child = getChildAt(i); if( child instanceof Button){ child.layout(mDisplayWidth/2-250, i*mDisplayHeight /12, mDisplayWidth/2+250, (i+1)*mDisplayHeight /12); }else{ child.layout(0, i*mDisplayHeight /12, mDisplayWidth, (i+1)*mDisplayHeight /6); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mDisplayWidth, mDisplayHeight/4); } }
/** * @Title: DurianSubLinearLayout.java * @Package com.durian.view * @Description: TODO * @author zhibao.liu from durian organization * @date 2015-12-22 下午03:11:33 * @version V1.0 */ package com.durian.view; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; /** * @ClassName: DurianSubLinearLayout * @Description: TODO * @author zhibao.liu Freelancer * @email warden_sprite@foxmail.com * @date 2015-12-22 下午03:11:33 * */ public class DurianSubLinearLayout extends LinearLayout { private final static String TAG="DurianSubLinearLayout"; private int mDisplayWidth=1200; private int mDisplayHeight=1824; private Button mButton; public DurianSubLinearLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub initView(context); } public DurianSubLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub initView(context); } public DurianSubLinearLayout(Context context) { super(context); // TODO Auto-generated constructor stub initView(context); } private void initView(Context context){ mButton=new Button(context); mButton.setText("Third Sublinear button"); addView(mButton); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub super.onLayout(changed, l, t, r, b); for (int i = 0; i < getChildCount(); i++) { Log.i(TAG, "*** count i : " + i); View child = getChildAt(i); child.layout(mDisplayWidth/2-250, 100, mDisplayWidth/2+250, mDisplayHeight /12+100); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mDisplayWidth, mDisplayHeight/4); } }
Activity的布局文件如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".DurianMainActivity" > <com.durian.view.DurianViewGroup android:layout_width="fill_parent" android:layout_height="fill_parent" > </com.durian.view.DurianViewGroup> </RelativeLayout>
程序中涉及到的View的背景:alhpa_background.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <stroke android:width="2dip" android:color="#ffff00"/> </shape>
layout_backgrond.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid
android:color="#ffffffff"/>
<stroke
android:width="2dip"
android:color="#ff00ff"/>
</shape>
其他的基本上都还好, 运行程序如下:
做出上面的程序,主要涉及到两个需要实现的方法:
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom)
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
每一个 View在构建时,都会执行onLayout(...)这个方法,在这个方法里面,通过:
for (int i = 0; i < getChildCount(); i++) { Log.i(TAG, "*** count i : " + i); View child = getChildAt(i); if (child instanceof Button) { child.layout(mDisplayWidth / 2 - 250, i * mDisplayHeight / 12, mDisplayWidth / 2 + 250, (i + 1) * mDisplayHeight / 12); } else { child.layout(0, i * mDisplayHeight / 12, mDisplayWidth, (i + 1) * mDisplayHeight / 6); } }
可以获得这个容器中所有子View的对象,并且通过view.layout重新确定在这个容器中的位置,同时需要注意,view.layout(....)四个参数是相对直接父容器而言的,即相对的,和android显示屏幕的尺寸有关系,但是没有直接的关系.
至于onMeasure(...)这个方式,在我的程序里面直接设置参量进去了,但是实际上面需要做一下变换:
setMeasuredDimension(mDisplayWidth, mDisplayHeight / 4);
一般情况可以如下:
//how to get actural this container size , please read following : int specSize_Widht = MeasureSpec.getSize(widthMeasureSpec); int specSize_Heigth = MeasureSpec.getSize(heightMeasureSpec);
获得到的specSize_Width和specSize_Height的尺寸实际仍然需要参考上一层父容器中onlayout中指定的尺寸大小,最终能够显示在屏幕,最终是由父容器中的Onlayout中分配的尺寸大小决定的.
既然上面给出了那么层级的按钮,可想而知,是用来处理事件的,下一篇继续.
代码参考:
android系统源代码 :
View.java,以及ViewRoot.java等部分.
相关文章推荐
- Android 返回按钮的实现
- Android M 新的运行时权限开发者需要知道的一切
- 【Android】SQLite实例(多线程下安全访问数据库)
- 47.Android 自定义PopupWindow技巧
- Android简单音乐播放实例
- Android系统提供了哪些东西,供我们可以开发出优秀的应用程序
- Android系统提供了哪些东西,供我们可以开发出优秀的应用程序
- Android Support V4, V7, V13的作用
- 快速开发框架dh 4000 roid的使用
- Android中插件开发篇之----应用换肤原理解析
- Android学习(3)---Fragment的学习
- Android 线程理解
- Android-Service
- Android开发常用
- android studio gradlew编译时proguardRelease报错
- Android中获取手机屏幕大小的方法
- Android Drawable中shape详解
- Android日期/时间选择器(工具类)
- android显式启动与隐式启动
- android- ScrollView与ListView冲突(最后一条Item显示不全)