前言

我K。今天竟然是情人节。对于资深的单身狗来说,简直是个噩耗,今天注定是各种秀恩爱。心塞中。。

。。

话题到此结束,管他什么情人节,今天给大家带来的是一个浮层的上下滑动,浮层滑动时分三种状态:所有显示、显

示一半、隐藏。可在浮层中加入ListView,GirdView,ImageView等等View。

详细的效果看以下的GIF图:

效果解说

1、在上面的浮层中我们能够看到存放着一个ListView。并能进行上下滚动,也就是说浮层的Touch事件须要在适

当的时候进行拦截,不传递给子View。

这时须要重写onInterceptTouchEvent()和onTouch()方法。

onInterceptTouchEvent和onTouch的介绍请參看以下:

1、onInterceptTouchEvent()是用于处理事件(类似于预处理。当然也能够不处理)并改变事件的传递方向,也就是

决定是否同意Touch事件继续向下(子控件)传递。一但返回True(代表事件在当前的viewGroup中会被处理),则向

下传递之路被截断(全部子控件将没有机会參与Touch事件),同一时候把事件传递给当前的控件的onTouchEvent()处

理;返回false。则把事件交给子控件的onInterceptTouchEvent()。

2、onTouchEvent()用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。也就是说在当前控件在处

理完Touch事件后,是否还同意Touch事件继续向上(父控件)传递,一但返回True,则父控件不用担心自己来处理

Touch事件。返回true,则向上传递给父控件(注:可能你会认为是否消费了有关系吗。反正我已经针对事件编写了

处理代码?答案是有差别。比方ACTION_MOVE或者ACTION_UP发生的前提是一定以前发生了ACTION_DOWN,假设你没有

消费ACTION_DOWN,那么系统会觉得ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。

2、在上图中能够看出。当进行上下滚动时具有滚动效果,能够通过下面代码实现:

ObjectAnimator anim=ObjectAnimator.ofFloat(this, "translationY", values);

实现原理

实现的原理事实上非常easy,我们所要做的就是在onInterceptTouchEvent和onTouch两个事件处理的方法中进行处理。

onInterceptTouchEvent的任务是推断何时拦截事件。交由onTouch处理。何时由子View进行事件处理。

依据上图能够非常清楚知道onInterceptTouchEvent所要做的工作。在onTuch的中最基本的操作是在获取滑动时的

MotionEvent.ACTION_MOVE中进行动画的处理。

到此为止仅仅说讲解了两个事件处理方法该做写什么。在图中能够看出。滑动时主要有三种状态。各自是所有显示

、显示一半、隐藏。

所有显示:当浮层所有显示时。这时浮层视图不应该继续向上滚动,这时须要在onInterceptTouchEvent中将事

件传递给它的子View进行处理;当向下滑动时,须要进行向下移动的动画处理,滑动一次。这时的浮层视图应该显示

一半。

显示一半:当浮层显示一半时。这时进行向上滑动时须要运行向上移动的动画处理,向下滑动时也一样。进行移

动的动画处理。进行隐藏浮层。

隐藏:当浮层进行隐藏时。能够通过点击对应的点击事件,使浮层从底部向上移动,并移动一半。

代码

以上是大体的思路。详细实现请參看以下的代码。

public class FloatingLayerView extends LinearLayout implements OnTouchListener {

	/**
* 视图显示类型。 */
private int type=ALL;
/**
* 浮层的高度。
*/
private int floating_height;
/**
* 浮层的宽度
*/
private int floating_width; /**
* 滑动高度
*/
private float move_height; /**
* 是否向下滑动。交由onTouch事件处理。 */
private boolean isCanHide=false;
/**
* 是否进行动画
*/
private boolean isCanAnimation=false; /**
* 触发拦截触摸事件时的坐标点。
* 按下:
* interceptTouch_X:按下时的X坐标点。
* interceptTouch_Y:按下时的Y坐标点。 * 滑动:
* interceptMove_X:滑动时的X坐标点。
* interceptMove_Y:滑动时的Y坐标点。
* 距离:
* interceptTouch_Move_X:从按下到滑动之间的距离(横向滑动)
* interceptTouch_Move_Y:从按下到滑动之间的距离(纵向滑动)
* 滑动距离:
* moveLength:依据此值推断是否进行了滑动。 */
private float interceptTouch_X;
private float interceptTouch_Y;
private float interceptMove_X;
private float interceptMove_Y;
private float interceptTouch_Move_X;
private float interceptTouch_Move_Y;
private int moveLength=10; /**
* 触发触摸事件时的坐标点
* down_X:按下时的X坐标点。
* down_Y:按下时的Y坐标点。 * move_X:移动时的X坐标点。 * move_Y:移动时的Y坐标点。 * down_move_X:横向滑动的距离。
* down_move_Y:纵向滑动的距离。
*/
private float down_X;
private float down_Y;
private float move_X;
private float move_Y;
private float down_move_X;
private float down_move_Y; /**
* 定义三种浮层显示类型
* 0:不显示 1:显示一半 2:所有显示
*/
private static final int NONE=0;
private static final int HALF=1;
private static final int ALL=2; public FloatingLayerView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnTouchListener(this);
} public FloatingLayerView(Context context) {
super(context);
} @Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
if(hasWindowFocus){
floating_width=getWidth();
floating_height=getHeight();
/**
* 每次滑动的距离是当前View宽度的三分之中的一个。
*/
move_height=floating_height/3;
}
super.onWindowFocusChanged(hasWindowFocus);
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
/**
* 当按下时获取x,y的坐标点。
*/
case MotionEvent.ACTION_DOWN:
interceptTouch_X = ev.getX();
interceptTouch_Y = ev.getY();
isCanAnimation=true;
break;
/**
* 当滑动时操作例如以下:
* 1、获取滑动距离
* 2、推断向上滑动还是向下滑动
* 3、向上滑动时
* 4、向下滑动时,推断当前显示方式:
* (1)、显示一半时。交由onTouch事件处理。
* (2)、所有显示时,是否向下滑动交由当前View的子View处理,
* 是否交由onTouch事件处理。 */
case MotionEvent.ACTION_MOVE:
interceptMove_X = ev.getX();
interceptMove_Y = ev.getY();
interceptTouch_Move_X = Math
.abs(interceptTouch_X - interceptMove_X);
interceptTouch_Move_Y = Math
.abs(interceptTouch_Y - interceptMove_Y);
/**
* 向下滑动
*/
if(interceptMove_Y>interceptTouch_Y&&interceptTouch_Move_Y>moveLength&&interceptTouch_Move_Y>interceptTouch_Move_X){
return isDounTransferOnTouch();
}
/**
* 向上滑动
*/
if(interceptTouch_Y>interceptMove_Y&&interceptTouch_Move_Y>moveLength&&interceptTouch_Move_Y>interceptTouch_Move_X){
return isUpTransferOnTouch();
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
} @Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
/**
* 当滑动时动画操作
*/
case MotionEvent.ACTION_MOVE:
down_X=interceptTouch_X;
down_Y=interceptTouch_Y;
move_X=event.getX();
move_Y=event.getY();
down_move_X=Math.abs(down_X-move_X);
down_move_Y=Math.abs(down_Y-move_Y);
/**
* 向下滑动
*/
if(move_Y>down_Y&&down_move_Y>moveLength&&getCanAnimation()){
downAnimationConfig();
}
/**
* 向上滑动
*/
if(down_Y>move_Y&&down_move_Y>moveLength&&getCanAnimation()){
upAnimationConfig();
}
/**
* 运行完上面动画处理后,停止运行动画
*/
setCanAnimation(false);
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true;
} /**
* 是否进行动画处理
* @return true:处理
*/
private boolean getCanAnimation(){
return isCanAnimation;
} /**
* 获取当前视图显示类型
* @return
*/
private int getType(){
return type;
} private void setType(int type){
this.type=type;
} /**
* 设置是否进行动画处理
* @param canAnimation
*/
private void setCanAnimation(boolean canAnimation){
this.isCanAnimation=canAnimation;
} /**
* 向下滑动时的动画处理
*/
private void downAnimationConfig(){
switch (getType()) {
case HALF://当视图显示一半时
half2None();
break;
case ALL://当视图所有显示时
all2Half();
break; default:
break;
}
} /**
* 向上滑动时的动画处理
*/
private void upAnimationConfig(){
switch (getType()) {
case HALF://当视图显示一半时
half2All();
break;
case ALL://当视图所有显示时
/**
* 当视图已经完整显示,再往
* 上滑动也就没不论什么意义进行
* 动画处理。
*/
break;
default:
break;
}
} /**
* 向下滑动时是否交由onTouch事件处理
* @return true:由onTouch事件处理,不传递给子View
*/
private boolean isDounTransferOnTouch(){
switch (type) {
case NONE:
break;
case HALF:
return true;
case ALL:
if(isCanHide){
return true;
}
break;
default:
break;
}
return false;
} /**
* 向上滑动时是否交由onTouch事件处理
* @return true:由onTouch事件处理。不传递给子View
*/
private boolean isUpTransferOnTouch(){
switch (type) {
case NONE:
break;
case HALF:
return true;
case ALL:
break;
default:
break;
}
return false;
} /**
* 当向下滑动时,当前视图显示一半,再往下滑动隐藏。 * type设置为NONE
*/
private void half2None(){
float[] values=new float[]{move_height,getHeight()};
startAnimation(values);
setType(NONE);
} /**
* 当向下滑动时。当前视图显示完整,再往下滑动视图显示一半。
* type设置为HALF
*/
private void all2Half(){
float[] values=new float[]{0,move_height};
startAnimation(values);
setType(HALF);
} /**
* 当向上滑动时,当前视图显示一半,再往上滑动,视图显示完整。
* type设置为ALL
*/
private void half2All(){
float[] values=new float[]{move_height,0};
startAnimation(values);
setType(ALL);
} /**
* 运行动画
* @param values
*/
private void startAnimation(float[] values){
AnimatorSet as=new AnimatorSet();
ObjectAnimator anim=ObjectAnimator.ofFloat(this, "translationY", values);
anim.setDuration(500);
as.playTogether(anim);
as.start();
} /**
* 当前视图显示完整时的动画处理
*/
private void all2None(){
float[] values=new float[]{0,getHeight()};
startAnimation(values);
setType(HALF);
} /**
* 隐藏浮层
*/
public void beforeInput(){
switch (getType()) {
case NONE:
break;
case HALF:
half2None();
break;
case ALL:
all2None();
break; default:
break;
}
} /**
* 显示浮层一半
*/
public void none2Half(){
float[] values=new float[]{getHeight(),move_height};
startAnimation(values);
setType(HALF);
} /**
* 显示所有浮层
*/
public void none2All(){
float[] values=new float[]{getHeight(),0};
startAnimation(values);
setType(HALF);
} /**
* 是否进行动画滚动
* @param canHide
*/
public void setCanHide(boolean canHide){
this.isCanHide=canHide;
} }

在代码中已经进行了非常具体的凝视。在代码的最后暴露了几个可调用的方法。能够通过这几个方法实现我们的滑动效

果。

在Activity中的通过GridView的OnScrollListener监听事件进行推断何时进行动画的滚动。何时停止,当然在FloatingLa

yerView能够加上想要加的View。比例如以下面在FloatingLayerView中加入了GirdView:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white" > <Button
android:id="@+id/btn_show"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:text="显示浮层" /> <Button
android:id="@+id/btn_hide"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_below="@id/btn_show"
android:text="隐藏浮层" /> <!-- 覆盖层 --> <com.example.floatinglayeranimtion.FloatingLayerView
android:id="@+id/activity_shine_ll_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/btn_hide"
android:layout_marginTop="40dp"
android:background="@android:color/holo_blue_dark"
android:visibility="visible" > <GridView
android:id="@+id/activity_shine_gv_all"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:horizontalSpacing="4dp"
android:listSelector="@null"
android:numColumns="4"
android:verticalSpacing="4dp" >
</GridView>
</com.example.floatinglayeranimtion.FloatingLayerView> </RelativeLayout>

Activity的代码例如以下:

public class MainActivity extends Activity implements OnClickListener {

	private Button btn_show;
private Button btn_hide;
private GridView gv_all; private TestAdapter testAdapter = new TestAdapter(); // 覆盖层
private FloatingLayerView mFloatingLayerView; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
addListener();
} private void initView() {
btn_show = (Button) findViewById(R.id.btn_show);
btn_hide = (Button) findViewById(R.id.btn_hide);
// 覆盖层
mFloatingLayerView = (FloatingLayerView) findViewById(R.id.activity_shine_ll_cover);
gv_all = (GridView) findViewById(R.id.activity_shine_gv_all); gv_all.setAdapter(testAdapter); } private void addListener() {
btn_show.setOnClickListener(this);
btn_hide.setOnClickListener(this);
gv_all.setOnScrollListener(scrollListener); } @Override
public void onClick(View v) {
switch (v.getId()) { // 显示浮层
case R.id.btn_show:
mFloatingLayerView.none2Half();
break; // 隐藏浮层
case R.id.btn_hide:
mFloatingLayerView.beforeInput();
break; }
} /** 覆盖层中GridView滑动监听 */
private OnScrollListener scrollListener = new OnScrollListener() { @Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
} @Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (firstVisibleItem == 0) {
mFloatingLayerView.setCanHide(true);
} else {
mFloatingLayerView.setCanHide(false);
} } }; // =============測试======================
private int[] images = new int[] { R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher, R.drawable.ic_launcher, R.drawable.ic_launcher,
R.drawable.ic_launcher }; class TestAdapter extends BaseAdapter { @Override
public int getCount() {
return images.length;
} @Override
public Object getItem(int position) {
return images[position];
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) { View view = LayoutInflater.from(MainActivity.this).inflate(
R.layout.image, null); ImageView imagView = (ImageView) view.findViewById(R.id.iv_show);
imagView.setBackgroundResource(images[position]);
return view;
} } }

OK,至此滑动的浮层已经实现了,欢迎大家吐槽。

-------------------------------------------------------------------------------------------------------------------------------------------------------

转载请注明出处:http://blog.csdn.net/hai_qing_xu_kong/article/details/47806881情绪控

项目GitHub地址:https://github.com/LinhaiGu/FloatingLayerAnimtion

Android实现浮层的上下滑动(支持内部加入View)的更多相关文章

  1. Android Widget 开发详解(二) +支持listView滑动的widget

    转载请标明出处:http://blog.csdn.net/sk719887916/article/details/47027263 不少开发项目中都会有widget功能,别小瞧了它,他也是androi ...

  2. Android实现多页左右滑动效果,支持子view动态创建和cache

    要实现多页滑动效果,主要是需要处理onTouchEvent和onInterceptTouchEvent,要处理好touch事件的子控件和父控件的传递问题. 滚动控制可以利用android的Scroll ...

  3. Android 实现两屏幕互相滑动

    Android 实现两屏幕互相滑动 下文来自: http://blog.csdn.net/song_shi_chao/article/details/7081664 ----------------- ...

  4. Android UI效果实现——Activity滑动退出效果

    更新说明: 1.在QQ网友北京-旭的提醒下,在SlideFrame的initilize方法中添加了focusable.focusableInTouch.clickable的状态设置,否则会导致部分情况 ...

  5. Android使用ViewFlipper实现左右滑动效果面

    在我的博客中,上次是使用ViewPager实现左右滑动的效果的,请看文章:Android使用ViewPager实现左右滑动效果. 这次我来使用ViewFlipper实现这种效果,好了,先看看效果吧: ...

  6. Android开发调试日志工具类[支持保存到SD卡]

    直接上代码: package com.example.callstatus; import java.io.File; import java.io.FileWriter; import java.i ...

  7. appcompat v21: 让 Android 5.0 前的设备支持 Material Design

    1. 十大Material Design开源项目 2. appcompat v21: 让 Android 5.0 前的设备支持 Material Design 主题 AppCompat已经支持最新的调 ...

  8. 【Java/Android性能优 4】PreloadDataCache支持预取的数据缓存,使用简单,支持多种缓存算法,支持不同网络类型,扩展性强

    本文转自:http://www.trinea.cn/android/preloaddatacache/ 本文主要介绍一个支持自动向前或向后获取新数据的缓存的使用及功能.Android图片内存缓存可见I ...

  9. Android防微信首页左右滑动切换

    大家看到微信首页切换效果有没有觉得很炫,滑动切换,点击底部bar瞬间切换,滑动切换渐变效果,线上效果图: 之前也在博客上看到别人的实现,再次基础上,我做了些优化.首先说下实现原理,大神略过,o(╯□╰ ...

随机推荐

  1. 【转】Linux账号管理之useradd

    转自:http://www.jb51.net/article/45848.htm Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然 ...

  2. [ SCOI 2009 ] 最长距离

    \(\\\) \(Description\) 一个\(N\times M\)的网格图中有一些坏点,图是四联通的. 你至多可以拿走\(K\)个坏点,求拿走后联通的点对中欧几里得距离最大是多少. \(N, ...

  3. drupal 8——图片组(list)在前台的显示顺序在登录状态和非登录状态不同

    问题描述:该页面是通过view来输出的,然而,登录状态下其页面中的图片组输出顺序是乱序的,而非登录状态下则根据id值升序输出. 原因:在原view配置页面中,没有配置默认的排序字段 解决方案:在vie ...

  4. [Android]异常7-Error:Configuration with name 'default' not found.

    背景:使用SVN更新代码,运行出现 异常原因: 可能一>缺少Modules 解决办法有: 解决一>Android Studio切换为Project,settings.gradle中引用和现 ...

  5. mvc EF 出现异常, 能提示出那个字段出现问题

    } catch (DbEntityValidationException ex) { message = "添加异常"; desc = " {" + ex.Me ...

  6. get传数组

    开发真的处处都是坑呀 ajax get请求,传数组,想当然的给了个json数组['','',''],结果500错误 正确的方式,多次赋值,见下图,后台会自动转数组

  7. smtplib.SMTPDataError: (554, b'DT:SPM 126 smtp

    报错信息 smtplib.SMTPDataError: (554, b'DT:SPM 126 smtp7,DsmowAA3uguL7e1cyvkyFw--.22553S3 1559096715,ple ...

  8. RabbitMQ在Ubuntu上的环境搭建

    1.修改/etc/apt/sources.list文件 A:命令:vi /etc/apt/sources.list B:在最后一行加上:deb http://www.rabbitmq.com/debi ...

  9. IO相关操作

    IO相关操作 对于IO操作而言,有四个基本的操作:open .read .write .close 我们来逐个解释.    在此之前我们先解释一下什么是文件描述符 文件描述符 操作系统通过一个整数开代 ...

  10. npm和gulp学习

    npm的使用 node Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,是一种JavaScript语言运行平台,和浏览器这个运行平台是同一个概念. npm np ...