我参考了这篇文章,我将它改了一下:
可动态布局的Android抽屉之基础
工程中需要这样的效果,左边和右边的Panel可以打开关闭:
我把左边和右边的Panel封装成2个类了。这里要特别注意,抽屉是需要“handler”的,我这里可以把任何View都看成“handler”,使用setBindView(View bindView)方法进行绑定“handler”。这样做的好处是“把手”可以独立于抽屉,可以任意控制把手的位置,而不需要把手跟着抽屉移动!
先看左边的Panel:
右边的Panel,需要注意构造函数多了viewBeside参数:
使用方法:
main.xml:
可动态布局的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;
- }
- }
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.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控件
- }
- }
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>