`

可左右两侧挤压傍边布局的Android抽屉

阅读更多
我参考了这篇文章,我将它改了一下:
可动态布局的Android抽屉之基础

工程中需要这样的效果,左边和右边的Panel可以打开关闭:



我把左边和右边的Panel封装成2个类了。这里要特别注意,抽屉是需要“handler”的,我这里可以把任何View都看成“handler”,使用setBindView(View bindView)方法进行绑定“handler”。这样做的好处是“把手”可以独立于抽屉,可以任意控制把手的位置,而不需要把手跟着抽屉移动!

先看左边的Panel:
import android.content.Context;
import android.os.AsyncTask;
import android.view.View;
import android.widget.LinearLayout;

public class LeftPanel extends LinearLayout{
	
	/**每次自动展开/收缩的范围*/
	private final static int SPEED=20;
	private int MAX_WIDTH=0;
	private Context mContext;

	public LeftPanel(Context context,int width,int height) {
		super(context);
		this.mContext=context;
		//设置Panel本身的属性
		LayoutParams lp=new LayoutParams(width, height);
		lp.leftMargin=-lp.width;
		MAX_WIDTH=Math.abs(lp.leftMargin);
		this.setLayoutParams(lp);
	}
	/**
	 * 
	 * @param context
	 * @param width
	 * @param height
	 * @param bindView
	 * @param contentView
	 */
	public LeftPanel(Context context,int width,int height,View bindView,View contentView) {
		this(context,width,height);
		setBindView(bindView);
		setContentView(contentView);
	}
	/**
	 * 把View放在Panel中
	 * @param v
	 */
	public void setContentView(View v){
		this.addView(v);
	}
	
	/**
	 * 绑定触发动画的View
	 * @param bindView
	 */
	public void setBindView(View bindView){
		bindView.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View v) {
				LayoutParams lp = (LayoutParams) getLayoutParams();
				if (lp.leftMargin < 0)// CLOSE的状态
					new AsynMove().execute(new Integer[] { SPEED });// 正数展开
				else if (lp.leftMargin >= 0)// OPEN的状态
					new AsynMove().execute(new Integer[] { -SPEED });// 负数收缩
			}
			
		});
	}
	
	class AsynMove extends AsyncTask<Integer, Integer, Void> {

		@Override
		protected Void doInBackground(Integer... params) {
			int times;
			if (MAX_WIDTH % Math.abs(params[0]) == 0)// 整除
				times = MAX_WIDTH / Math.abs(params[0]);
			else
				times = MAX_WIDTH / Math.abs(params[0]) + 1;// 有余数

			for (int i = 0; i < times; i++) {
				publishProgress(params);
				try {
					Thread.sleep(Math.abs(params[0]));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... params) {
			LayoutParams lp = (LayoutParams)getLayoutParams();
			if (params[0] < 0){//关闭
				lp.leftMargin = Math.max(lp.leftMargin + params[0],-MAX_WIDTH);
			}
			else{//打开
				lp.leftMargin = Math.min(lp.leftMargin + params[0],MAX_WIDTH);
			}
			if(lp.leftMargin==0 && onPanelStatusChangedListener!=null){//展开之后
				onPanelStatusChangedListener.onPanelOpened(LeftPanel.this);//调用OPEN回调函数
			}
			else if(lp.leftMargin==-MAX_WIDTH && onPanelStatusChangedListener!=null){//收缩之后
				onPanelStatusChangedListener.onPanelClosed(LeftPanel.this);//调用CLOSE回调函数
			}
			setLayoutParams(lp);
		}
	}
	
	public interface OnPanelStatusChangedListener{
		void onPanelOpened(LeftPanel panel);
		void onPanelClosed(LeftPanel panel);
	}
	private OnPanelStatusChangedListener onPanelStatusChangedListener;
	public void setOnPanelStatusChangedListener(OnPanelStatusChangedListener onPanelStatusChangedListener){
		this.onPanelStatusChangedListener=onPanelStatusChangedListener;
	}
}

右边的Panel,需要注意构造函数多了viewBeside参数:
import android.content.Context;
import android.os.AsyncTask;
import android.view.View;
import android.widget.LinearLayout;

public class RightPanel extends LinearLayout{
	
	/**每次自动展开/收缩的范围*/
	private final static int SPEED=20;
	private int MAX_WIDTH=0;
	private Context mContext;

	/**
	 * viewBeside自动布局以适应Panel展开/收缩的空间变化
	 *
	 */	
	public RightPanel(Context context,View viewBeside,int width,int height) {
		super(context);
		this.mContext=context;
	
		//必须改变Panel左侧组件的weight属性
		LayoutParams p=(LayoutParams) viewBeside.getLayoutParams();
		p.weight=1;//支持挤压
		viewBeside.setLayoutParams(p);
		
		//设置Panel本身的属性
		LayoutParams lp=new LayoutParams(width, height);
		lp.rightMargin=-lp.width;
		MAX_WIDTH=Math.abs(lp.rightMargin);
		this.setLayoutParams(lp);
		
	}
	/**
	 * 
	 * @param context
	 * @param otherView
	 * @param width
	 * @param height
	 * @param bindView
	 * @param contentView
	 */
	public RightPanel(Context context,View viewBeside,int width,int height,View bindView,View contentView) {
		this(context,viewBeside,width,height);
		setBindView(bindView);
		setContentView(contentView);
	}
	
	/**
	 * 把View放在Panel中
	 * @param v
	 */
	public void setContentView(View v){
		this.addView(v);
	}
	
	/**
	 * 绑定触发动画的View
	 * @param bindView
	 */
	public void setBindView(View bindView){
		bindView.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View v) {
				LayoutParams lp = (LayoutParams) getLayoutParams();
				if (lp.rightMargin < 0)// CLOSE的状态
					new AsynMove().execute(new Integer[] { SPEED });// 正数展开
				else if (lp.rightMargin >= 0)// OPEN的状态
					new AsynMove().execute(new Integer[] { -SPEED });// 负数收缩
			}
			
		});
	}
	
	class AsynMove extends AsyncTask<Integer, Integer, Void> {

		@Override
		protected Void doInBackground(Integer... params) {
			int times;
			if (MAX_WIDTH % Math.abs(params[0]) == 0)// 整除
				times = MAX_WIDTH / Math.abs(params[0]);
			else
				times = MAX_WIDTH / Math.abs(params[0]) + 1;// 有余数

			for (int i = 0; i < times; i++) {
				publishProgress(params);
				try {
					Thread.sleep(Math.abs(params[0]));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... params) {
			LayoutParams lp = (LayoutParams)getLayoutParams();
			if (params[0] < 0)
				lp.rightMargin = Math.max(lp.rightMargin + params[0], -MAX_WIDTH);
			else
				lp.rightMargin = Math.min(lp.rightMargin + params[0], 0);

			if(lp.rightMargin==0 && onPanelStatusChangedListener!=null){//展开之后
				onPanelStatusChangedListener.onPanelOpened(RightPanel.this);//调用OPEN回调函数
			}
			else if(lp.rightMargin==-MAX_WIDTH && onPanelStatusChangedListener!=null){//收缩之后
				onPanelStatusChangedListener.onPanelClosed(RightPanel.this);//调用CLOSE回调函数
			}
			setLayoutParams(lp);
		}
	}
	
	public interface OnPanelStatusChangedListener{
		void onPanelOpened(RightPanel panel);
		void onPanelClosed(RightPanel panel);
	}
	private OnPanelStatusChangedListener onPanelStatusChangedListener;
	public void setOnPanelStatusChangedListener(OnPanelStatusChangedListener onPanelStatusChangedListener){
		this.onPanelStatusChangedListener=onPanelStatusChangedListener;
	}

}


使用方法:
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.LinearLayout.LayoutParams;

public class App extends Activity {
	public LeftPanel leftPanel;
	public RightPanel rightPanel;
	public LinearLayout container;
	public Button btn_0,btn_1;
	private View tv;
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		container=(LinearLayout)findViewById(R.id.container);
		btn_0 = (Button) findViewById(R.id.btn_0);
		btn_1 = (Button) findViewById(R.id.btn_1);
		tv = findViewById(R.id.tv);
		
		//新建测试组件
		TextView content0=new TextView(this);
		content0.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
		content0.setText("左边的panel");
		content0.setGravity(Gravity.CENTER);
		content0.setTextColor(Color.RED);
		content0.setBackgroundColor(Color.WHITE);
		
		//新建测试组件
		TextView content1=new TextView(this);
		content1.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
		content1.setText("右边的panel");
		content1.setGravity(Gravity.CENTER);
		content1.setTextColor(Color.RED);
		content1.setBackgroundColor(Color.WHITE);
		
		leftPanel=new LeftPanel(this,120,LayoutParams.FILL_PARENT);
		leftPanel.setBindView(btn_0);
		leftPanel.setContentView(content0);
		leftPanel.setOnPanelStatusChangedListener(new LeftPanel.OnPanelStatusChangedListener() {
			
			@Override
			public void onPanelOpened(LeftPanel panel) {
				// TODO Auto-generated method stub
				Log.i("tag", "======onPanelOpened=======");
			}
			
			@Override
			public void onPanelClosed(LeftPanel panel) {
				// TODO Auto-generated method stub
				Log.i("tag", "======onPanelClosed=======");
			}
		});
		
		container.addView(leftPanel,0);//加入Panel控件
		//
		rightPanel=new RightPanel(this,tv,120,LayoutParams.FILL_PARENT);
		rightPanel.setBindView(btn_1);
		rightPanel.setContentView(content1);
		rightPanel.setOnPanelStatusChangedListener(new RightPanel.OnPanelStatusChangedListener() {
			
			@Override
			public void onPanelOpened(RightPanel panel) {
				// TODO Auto-generated method stub
				Log.i("tag", "======onPanelOpened=======");
			}
			
			@Override
			public void onPanelClosed(RightPanel panel) {
				// TODO Auto-generated method stub
				Log.i("tag", "======onPanelClosed=======");
			}
		});
		container.addView(rightPanel);//加入Panel控件
	}

}

main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="fill_parent" 
	android:layout_height="fill_parent"
	android:orientation="vertical"
	>
	<LinearLayout
		android:id="@+id/container"
		android:layout_width="fill_parent" 
		android:layout_height="fill_parent"
		android:orientation="horizontal"
		android:layout_weight="1"
		>
		<TextView  android:id="@+id/tv" 
			android:layout_width="fill_parent"
			android:layout_height="fill_parent" 
			android:gravity="center"
			android:text="hello,squeeze me."
			/>
	</LinearLayout>
	<LinearLayout
		android:layout_width="fill_parent" 
		android:layout_height="wrap_content"
		android:orientation="horizontal"
		android:gravity="center"
		>
		<Button android:id="@+id/btn_0" 
				android:layout_width="wrap_content"
				android:layout_height="wrap_content" 
				android:text="left"
				/>
		<Button android:id="@+id/btn_1" 
				android:layout_width="wrap_content"
				android:layout_height="wrap_content" 
				android:text="right"
				/>
	</LinearLayout>
</LinearLayout>
  • 大小: 28.7 KB
分享到:
评论
2 楼 蜗牛/ 2012-05-31  
感谢你提供这篇文章!
1 楼 nidehengji 2012-02-08  
灰常灰常感谢楼主

相关推荐

    “可动态布局”的Android抽屉组件之完整篇

    本篇将深入探讨如何创建一个可动态布局的Android抽屉组件,提供一个完整的实现案例源码。 首先,抽屉组件的基本概念:DrawerLayout是Android提供的一个视图容器,它可以包含两个主要区域——主内容视图和一个或多个...

    Android抽屉效果上下抽屉

    在Android应用开发中,"抽屉效果"通常指的是 DrawerLayout 的实现,它是Android设计支持库中的一个组件,用于创建导航抽屉(Navigation Drawer)效果。这个效果常见于许多应用程序,如Google Maps、Gmail等,它允许...

    “可动态布局”的Android抽屉组件之构建基础

    2. **多抽屉支持**:除了标准的单侧抽屉,ExPanel(1)可能支持左右两侧都设置抽屉。 3. **内容区域联动**:在抽屉打开时,主内容区域可能会有相应的响应,比如半透明效果或禁止触摸事件。 4. **手势识别**:除了点击...

    android左右抽屉效果

    标题中的"android左右抽屉效果"指的是在Android应用中实现可以从屏幕左侧或右侧滑出的抽屉菜单。 抽屉效果的实现主要依赖于Android的`DrawerLayout`组件,它是Android SDK中的一个视图容器,能够承载主内容视图和一...

    Android 抽屉实现

    `SlidingDrawer`是Android早期版本中的一个自定义视图,它可以创建一个可滑动的抽屉,包含顶部和底部的柄以及内容区域。 **SlidingDrawer的使用步骤:** 1. **在布局XML中添加SlidingDrawer:** 在你的布局文件中...

    Android 侧边抽屉效果

    在Android应用开发中,"侧边抽屉效果"(通常称为侧滑菜单或抽屉布局)是一种常见的设计模式,用于实现应用的主要导航功能。这种效果允许用户从屏幕边缘滑动,展示一个隐藏的菜单,通常包含应用的不同部分或设置选项...

    Android 之抽屉效果(上下抽屉)

    在Android开发中,抽屉效果通常指的是模仿物理抽屉开合动作的一种界面交互设计,它为用户提供了一种隐藏和展示内容的方式。这种效果在很多应用中都有应用,比如导航菜单、设置面板等。本项目“Android之抽屉效果...

    android抽屉效果左右滑出

    在本篇内容中,我们将深入探讨如何使用Android支持库中的`android-support-v4.jar`来实现这种左右滑出的抽屉效果。 首先,我们需要引入`android-support-v4.jar`库。这个库包含了对早期Android版本的支持,提供了...

    超爽的android抽屉效果

    超爽的android抽屉效果. 超爽的android抽屉效果. 超爽的android抽屉效果. 超爽的android抽屉效果. 超爽的android抽屉效果. 超爽的android抽屉效果. 超爽的android抽屉效果. 超爽的android抽屉效果. 超爽的android...

    Android左右滑动抽屉菜单官方demo

    标题“Android左右滑动抽屉菜单官方demo”指的是Android官方提供的一个示例项目,展示了如何在应用中实现左右滑动的抽屉菜单。这个官方Demo是基于`support-v4`库的,`support-v4.jar`是Android的一个重要库,它为...

    Android使用DrawerLayout创建左右两个抽屉菜单

    本教程将详细讲解如何在Android项目中使用DrawerLayout创建左右两个抽屉菜单。 首先,我们需要了解 DrawerLayout 的基本结构。DrawerLayout 是一个可以包含多个视图的布局容器,其中至少包括主内容视图(通常是屏幕...

    android抽屉结合Fragment

    `Fragment`是Android中用来展示用户界面的一个可重用组件,它可以被添加到`Activity`的布局中,也可以被替换或移除。在抽屉中选择不同的导航项时,我们可以动态地替换`Activity`中的`Fragment`,从而实现内容的切换...

    android上下左右抽屉

    总的来说,"android上下左右抽屉"项目涵盖了Android抽屉布局的多个方面,包括基本原理、实现方式、自定义扩展以及测试调试等。开发者可以通过这个项目学习到如何在Android应用中创建丰富的交互体验。

    android类似双向抽屉效果实现

    `DrawerLayout`是Android SDK中的一个布局容器,它可以容纳一个或两个抽屉视图,通常是从屏幕左侧或右侧滑出。在XML布局文件中,你可以将主内容视图和抽屉视图分别作为`DrawerLayout`的子元素来设置。 以下是一个...

    从gitHub上整理出Android抽屉效果,包括左滑,右滑,上滑,下滑,想要实现的任何菜单效果都有

    抽屉布局(DrawerLayout)是Android SDK中的一个视图组件,它允许在主屏幕边缘滑出一个或两个“抽屉”式的子视图。通常,左侧抽屉用于展示主要功能的导航菜单,而右侧抽屉可以用于其他附加信息或者设置。 在该项目...

    Android 抽屉效果的实现

    在Android应用开发中,抽屉效果(DrawerLayout)是一种常见的设计模式,用于创建侧滑菜单,用户可以从屏幕边缘向内滑动来展示或隐藏菜单。这个功能在许多应用中都有体现,比如Google Maps、Facebook等。`Android_v4_...

    android 左右侧滑抽屉菜单demo

    标题“android 左右侧滑抽屉菜单demo”指的是一个具体的Android项目示例,演示如何创建并实现这种功能。 抽屉菜单在Android SDK中是通过`android.widget.DrawerLayout`类来实现的。这是一个视图容器,允许开发者在...

    android抽屉组件实例

    通过学习和实践这个实例,初学者不仅可以掌握抽屉组件的基本用法,还能进一步理解Android布局和事件处理机制,为今后的Android开发打下坚实的基础。记得在实际操作过程中,结合具体的代码示例和项目需求,不断探索和...

Global site tag (gtag.js) - Google Analytics