zoukankan      html  css  js  c++  java
  • ScrollView反弹效果 仿小米私密短信效果

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/28441197

    现在很多APP都给ScrollView添加了反弹效果,QQ、小米私密短信等。恰好在网上看到一个类:BounceScrollView ,

    原创地址是:http://blog.csdn.net/h7870181/article/details/8960430 , 可惜作者没有提供一个效果图,于是我发现小米短信列表页往下拉,有反弹效果,且拉到1/3以上时,会打开私密短信列表,小米的用户可以试试。

    我在作者BounceScrollView 类的基础上修改了一下,写了一个例子,给大家分享下。

    效果图:(模拟器的效果不佳,凑合可以看出来效果)



    1、首先是布局文件:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
      >
    
        <com.example.zhy_bouncescrollview02.BounceScrollView
            android:background="@drawable/shakehideimg_man"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/id_scrollView" >
    
            <com.example.zhy_bouncescrollview02.MyListView
                android:background="#fff"
                android:id="@+id/id_listView"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" >
            </com.example.zhy_bouncescrollview02.MyListView>
        </com.example.zhy_bouncescrollview02.BounceScrollView>
    
    </RelativeLayout>
    

    一个自定义的ScrollView内部包含着一个自定义的ListView,自定义ScrollView是为了添加反弹效果,自定义ListView是为了解决ScrollView和ListView嵌套产生的问题。

    2、BounceScrollView

    package com.example.zhy_bouncescrollview02;
    
    import android.content.Context;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.TranslateAnimation;
    import android.widget.ScrollView;
    
    /**
     * 支持上下反弹效果的ScrollView
     * 
     * @author zhy
     * 
     */
    public class BounceScrollView extends ScrollView
    {
    
    	private boolean isCalled ; 
    	
    	private Callback mCallback;
    
    	/**
    	 * 包含的View
    	 */
    	private View mView;
    	/**
    	 * 存储正常时的位置
    	 */
    	private Rect mRect = new Rect();
    
    	/**
    	 * y坐标
    	 */
    	private int y;
    
    	private boolean isFirst = true;
    
    	public BounceScrollView(Context context, AttributeSet attrs)
    	{
    		super(context, attrs);
    	}
    
    	/***
    	 * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate
    	 * 方法,也应该调用父类的方法,使该方法得以执行.
    	 */
    	@Override
    	protected void onFinishInflate()
    	{
    		if (getChildCount() > 0)
    			mView = getChildAt(0);
    		super.onFinishInflate();
    	}
    
    	@Override
    	public boolean onTouchEvent(MotionEvent ev)
    	{
    		if (mView != null)
    		{
    			commonOnTouch(ev);
    		}
    
    		return super.onTouchEvent(ev);
    	}
    
    	private void commonOnTouch(MotionEvent ev)
    	{
    		int action = ev.getAction();
    		int cy = (int) ev.getY();
    		switch (action)
    		{
    		case MotionEvent.ACTION_DOWN:
    			break;
    		/**
    		 * 跟随手指移动
    		 */
    		case MotionEvent.ACTION_MOVE:
    
    			int dy = cy - y;
    			if (isFirst)
    			{
    				dy = 0;
    				isFirst = false;
    			}
    			y = cy;
    
    			if (isNeedMove())
    			{
    				if (mRect.isEmpty())
    				{
    					/**
    					 * 记录移动前的位置
    					 */
    					mRect.set(mView.getLeft(), mView.getTop(),
    							mView.getRight(), mView.getBottom());
    				}
    
    				mView.layout(mView.getLeft(), mView.getTop() + 2 * dy / 3,
    						mView.getRight(), mView.getBottom() + 2 * dy / 3);
    
    				if (shouldCallBack(dy))
    				{
    					if (mCallback != null)
    					{
    						if(!isCalled)
    						{
    							isCalled = true ; 
    							resetPosition();
    							mCallback.callback();
    							
    							
    						}
    					}
    				}
    			}
    
    			break;
    		/**
    		 * 反弹回去
    		 */
    		case MotionEvent.ACTION_UP:
    			if (!mRect.isEmpty())
    			{
    				resetPosition();
    			}
    			break;
    
    		}
    	}
    
    	/**
    	 * 当从上往下,移动距离达到一半时,回调接口
    	 * 
    	 * @return
    	 */
    	private boolean shouldCallBack(int dy)
    	{
    
    		if (dy > 0 && mView.getTop() > getHeight() / 2)
    			return true;
    		return false;
    	}
    
    	private void resetPosition()
    	{
    		Animation animation = new TranslateAnimation(0, 0, mView.getTop(),
    				mRect.top);
    		animation.setDuration(200);
    		animation.setFillAfter(true);
    		mView.startAnimation(animation);
    		mView.layout(mRect.left, mRect.top, mRect.right, mRect.bottom);
    		mRect.setEmpty();
    		isFirst = true;
    		isCalled = false ; 
    	}
    
    	/***
    	 * 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度
    	 * 
    	 * getHeight():获取的是屏幕的高度
    	 * 
    	 * @return
    	 */
    	public boolean isNeedMove()
    	{
    		int offset = mView.getMeasuredHeight() - getHeight();
    		int scrollY = getScrollY();
    		// 0是顶部,后面那个是底部
    		if (scrollY == 0 || scrollY == offset)
    		{
    			return true;
    		}
    		return false;
    	}
    
    	public void setCallBack(Callback callback)
    	{
    		mCallback = callback;
    	}
    
    	interface Callback
    	{
    		void callback();
    	}
    
    }
    

    主要就是监听onTouchEvent,当MOVE时,ScrollView中的控件跟随手指移动,UP时恢复原来的位置;当达到1/2时,会调用用户设置的回调,细节就自己看代码了。

    3、MyListView

    package com.example.zhy_bouncescrollview02;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.widget.ListView;
    
    /**
     * 解决ScrollView与ListView的嵌套问题
     * @author zhy
     * 
     */
    public class MyListView extends ListView
    {
    
    	public MyListView(Context context, AttributeSet attrs)
    	{
    		super(context, attrs);
    	}
    
    	public MyListView(Context context, AttributeSet attrs, int defStyle)
    	{
    		super(context, attrs, defStyle);
    	}
    
    	public MyListView(Context context)
    	{
    		super(context);
    	}
    
    	@Override
    	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    	{
    
    		/**
    		 * 解决ScrollView与ListView的嵌套问题
    		 */
    		int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
    				MeasureSpec.AT_MOST);
    
    		super.onMeasure(widthMeasureSpec, expandSpec);
    	}
    
    }
    

    4、主Activity

    package com.example.zhy_bouncescrollview02;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import com.example.zhy_bouncescrollview02.BounceScrollView.Callback;
    
    public class MainActivity extends Activity
    {
    
    	private ListView mListView;
    	private BounceScrollView mScrollView;
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState)
    	{
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		mScrollView = (BounceScrollView) findViewById(R.id.id_scrollView);
    		mScrollView.setCallBack(new Callback()
    		{
    
    			@Override
    			public void callback()
    			{
    				Toast.makeText(MainActivity.this, "you can do something!", 0)
    						.show();
    				Intent intent = new Intent(MainActivity.this,
    						SecondActivity.class);
    				startActivity(intent);
    				overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
    			}
    		});
    		mListView = (ListView) findViewById(R.id.id_listView);
    		mListView.setAdapter(new ArrayAdapter<String>(this,
    				android.R.layout.simple_list_item_1, new ArrayList<String>(
    						Arrays.asList("Hello", "World", "Welcome", "Java",
    								"Android", "Lucene", "C++", "C#", "HTML",
    								"Welcome", "Java", "Android", "Lucene", "C++",
    								"C#", "HTML"))));
    	}
    
    }
    

    MainActivity代码也很简单,初始化两个控件,设置了下ScrollView的Callback。



    好了,好几天没写代码了,就这样吧。


    源码点击下载







    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    開始Unity3D的学习之旅
    提供一个免费的CSDN下载账号
    SIP入门(二):建立SIPserver
    设计模式之6大原则(6)开闭原则
    怎样利用App打造自明星实现自盈利
    BackTrack5 (BT5)无线password破解教程之WPA/WPA2-PSK型无线password破解
    机房收费重构——关于面向对象和分层的纠结
    JAVA反射机制
    php实现工厂模式
    freemarker中的round、floor和ceiling数字的舍入处理
  • 原文地址:https://www.cnblogs.com/dingxiaoyue/p/4924944.html
Copyright © 2011-2022 走看看