zoukankan      html  css  js  c++  java
  • Android实现浮层的上下滑动(支持内部加入View)

    前言


    我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



  • 相关阅读:
    解决UITableView中Cell重用机制导致内容出错的方法总结
    Hdu 1052 Tian Ji -- The Horse Racing
    Hdu 1009 FatMouse' Trade
    hdu 2037 今年暑假不AC
    hdu 1559 最大子矩阵
    hdu 1004 Let the Balloon Rise
    Hdu 1214 圆桌会议
    Hdu 1081 To The Max
    Hdu 2845 Beans
    Hdu 2955 Robberies 0/1背包
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7112615.html
Copyright © 2011-2022 走看看