android自定义实现抽屉SlidingDrawer的功能
最近项目中需要实现上拉功能,首先想到的就是Android本身自带的抽屉SlidingDrawer,最后也实现了不过,出现的问题就是设置背景色问题,handler和content是两个不同的部分,这就造成图片要做成两部分,从而产生两个部分图片看起来不是一个整体,而且我这个上拉功能,里面要实现一个水平滚动功能,而SlidingDrawer还有其他的限制,同时官方给出api 17以后,这个功能已经废弃,所以自己自定这样一个上拉功能是必须的。
这里我是继承LinearLayout同时实现GestureDetector.OnGestureListener来实现上拉功能。下面是代码:
package com.example.test; import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.LinearLayout;
import android.widget.RelativeLayout; public class PanelBom extends LinearLayout implements GestureDetector.OnGestureListener{ GestureDetector mGesture = null;
private boolean isScrolling = false;
private int MAX_HEIGHT = 80;//拖动的最大高度,当前布局位于父布局下面-80位置,这个仅仅是调试参数,这个变量是动态设置的。
private float mScrollX; // 滑块滑动距离
public PanelBom(Context context) {
super(context);
init();
}
public PanelBom(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
//初始化一些参数
public void init(){
mGesture = new GestureDetector(this);
mGesture.setIsLongpressEnabled(false);
setBackgroundResource(R.drawable.button_bar);
} @Override
public boolean onTouchEvent(MotionEvent event) {
if (MotionEvent.ACTION_UP == event.getAction() && isScrolling == true) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)getLayoutParams();
// 缩回去
if (layoutParams.bottomMargin < -MAX_HEIGHT / 2) {
new AsynMove().execute(-20);//负--往下
} else {
new AsynMove().execute(20);//正--往上
}
}
return mGesture.onTouchEvent(event);
}
//Touch down时触发
@Override
public boolean onDown(MotionEvent e) {
mScrollX = 0;
isScrolling = false;
// 将之改为true,不然事件不会向下传递.
return true;
}
//Touch了还没有滑动时触发
@Override
public void onShowPress(MotionEvent e) { }
@Override
public boolean onSingleTapUp(MotionEvent e) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
// 说明在上面,要往下
if (layoutParams.bottomMargin >= 0) {
new AsynMove().execute(-20);//负--往下
} else {
new AsynMove().execute(20);//正--往上
}
return true;
}
//Touch了滑动时触发
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
isScrolling = true;
mScrollX += distanceY;
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)getLayoutParams();
layoutParams.bottomMargin += mScrollX;
if (layoutParams.bottomMargin >= 0) {
isScrolling = false;// 拖过头了不需要再执行AsynMove了
layoutParams.bottomMargin = 0;
} else if (layoutParams.bottomMargin <= -MAX_HEIGHT) {
// 拖过头了不需要再执行AsynMove了
isScrolling = false;
layoutParams.bottomMargin = -MAX_HEIGHT;
}
setLayoutParams(layoutParams);
return false;
}
//Touch了不移动一直Touch down时触发
@Override
public void onLongPress(MotionEvent e) { }
//Touch了滑动一点距离后,up时触发。
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
//异步更新布局的位置
class AsynMove extends AsyncTask<Integer, Integer, Void> {
@Override
protected Void doInBackground(Integer... params) {
int times = 0;
int divi = Math.abs(params[0]);
if (MAX_HEIGHT % divi == 0)// 整除
times = MAX_HEIGHT / Math.abs(params[0]);
else
times = MAX_HEIGHT / divi + 1;// 有余数 for (int i = 0; i < times; i++) {
publishProgress(params[0]);
try {
Thread.sleep(divi);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
if (values[0] < 0) {
layoutParams.bottomMargin = Math.max(layoutParams.bottomMargin + values[0], -MAX_HEIGHT);
} else {
layoutParams.bottomMargin = Math.min(layoutParams.bottomMargin + values[0], 0);
}
setLayoutParams(layoutParams); super.onProgressUpdate(values);
}
}
}
主界面:
package com.example.test; import android.app.Activity;
import android.os.Bundle;
import android.widget.RelativeLayout; public class Main5 extends Activity{ RelativeLayout Parent;
PanelBom panelBom;
RelativeLayout.LayoutParams parentParams;
RelativeLayout.LayoutParams paneBomParams;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Parent = new RelativeLayout(getApplicationContext());
panelBom = new PanelBom(getApplicationContext());
parentParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
paneBomParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 150);
paneBomParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
paneBomParams.bottomMargin = -80;
Parent.addView(panelBom, paneBomParams);
setContentView(Parent, parentParams);
} }
实现的效果是:
拖拉,点击实现上拉功能,效果图如下:
android自定义实现抽屉SlidingDrawer的功能的更多相关文章
- Android -- 滑式抽屉SlidingDrawer(非原创)
SlidingDrawer(滑动式抽屉)隐藏屏外的内容,并允许用户拖拽一个handle以显示隐藏的内容.SlidingDrawer可以在垂直或者水平使用.它由两个子视图组成:一个是用户拖拽的handl ...
- android 自定义view之选座功能
效果图: 界面比较粗糙,主要看原理. 这个界面主要包括以下几部分 1.座位 2.左边的排数 3.左上方的缩略图 4.缩略图中的红色区域 5.手指移动时跟随移动 6.两个手指缩放时跟随缩放 主要技术点 ...
- Android控件之SlidingDrawer(滑动式抽屉)详解与实例
SlidingDrawer效果想必大家也见到过,它就是1.5模拟器上进入应用程序列表的效果.下面是截图 一.简介 SlidingDrawer隐藏屏外的内容,并允许用户通过handle以显示隐藏内容.它 ...
- Android抽屉(SlidingDrawer --类似android通知栏下拉效果)
Android抽屉(SlidingDrawer)的实现发 - 红黑联盟http://www.2cto.com/kf/201301/182507.html 可动态布局的Android抽屉之基础http: ...
- (转)[原] Android 自定义View 密码框 例子
遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 ...
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- [原] Android 自定义View步骤
例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能 ...
- [原] Android 自定义View 密码框 例子
遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 ...
- Android 自定义title 之Action Bar
Android 自定义title 之Action Bar 2014-06-29 飞鹰飞龙... 摘自 博客园 阅 10519 转 25 转藏到我的图书馆 微信分享: Action Ba ...
随机推荐
- UVa 10330 Power Transmission / 最大流
最大流 这题有很多起点和终点 在取2个点(0和n+1) 作为唯一的起点和终点 此外每个点也有容量限制 建图时每条边上的容量为这条边和2个端的容量的最小值 然后EK就行 #include <cst ...
- android开发之Intent.setFlags()_让Android点击通知栏信息后返回正在运行的程序
android开发之Intent.setFlags()_让Android点击通知栏信息后返回正在运行的程序 在应用里使用了后台服务,并且在通知栏推送了消息,希望点击这个消息回到activity ...
- HTML5小游戏《智力大拼图》发布,挑战你的思维风暴
一,前言 本 游戏 是鄙人研究lufylegend数日之后,闲暇之余写下的.本游戏运用全新的技术 html 5写成的.游戏引擎为国产的lufylegend.js,大家可以去它的官网看看.游戏处于测 ...
- windows进程清理脚本
公司统一配的笔记本Thinkpad T440p,超级难用,常常内存占满.硬盘卡死,还管不了机!心里那个不爽啊!哎,不说了. 自己写了个脚本,用来强制关闭不须要的进程. 脚本例如以下: -------- ...
- Git现实(四)状态转换
前Git实战(三)环境搭建博文.我们大致解说了一下git的环境安装.今天我们解说一下Git的状态转换. 学习版本号控制工具.对工具进行版本号控制之间的状态转换很重要. 毕竟Git仅仅是一个工具,假设不 ...
- VirtualBox安装及使用说明和虚拟机安装XP系统图文教程
virtualbox是一款开源的虚拟机软件,它能够支持多种操作系统的安装如:Solaris.Windows.DOS.Linux.OS/2 Warp.BSD等系统作为client操作系统,而且最新版本号 ...
- 基于visual Studio2013解决面试题之1006判断升序
题目
- JS将秒换成时分秒
function formatSeconds(value) { var theTime = parseInt(value);// 秒 var theTime1 = 0;// 分 va ...
- 真机測试时的错误:No matching provisioning profiles found
1.出现错误的原因是这种---- 公司接收一个外包项目,原来做真机測试的时候,用的是公司申请的苹果开发人员账号.如今项目结束了,准备上线,但客户要求使用客户自己的苹果开发人员是账号上线,于是就用客户的 ...
- sqlserver bak还原
一.查看: restore filelistonly from disk='F:\Db\A_backup.bak' 二.还原:RESTORE DATABASE AFROM DISK = 'F:\Db\ ...