安卓自定义Scrollview,实现卷帘效果
这个效果和网易彩票安卓客户端的双色球主页下拉效果差不多。公司也是做彩票的,想要一个这样的效果。开始有思路,但是实现起来还是挺麻烦的,逻辑不好理,经过一番研究,果然不负有心人。终于完美实现。分享给大家......
默认效果:
向下滑动后:
这里其实有很多细节,比如下滑高度小于卷帘的1/2,就弹回原处,大于1/2就自动弹到底,有一个弹性的效果。
当然上滑的时候也是,滑动距离小于1/2,还是留在底部,大于1/2,就弹回最顶部。
当你一进来,不下拉,就不会弹出卷帘,往上滑的时候就会滑动下面的内容,再次往下滑动,也不会弹出卷帘,而是要释放,再滑动一次,这样可以明显知道卷帘和下面的不是连在一起的。
布局文件代码:
<?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:background="#f6f6f6" android:orientation="vertical" > <RelativeLayout android:layout_width="fill_parent" android:layout_height="52dip" android:layout_gravity="center" android:background="#d80702" > <TextView android:layout_width="wrap_content" android:layout_height="fill_parent" android:gravity="center" android:paddingLeft="15dip" android:text="双色球-普通" android:textColor="#ffffff" android:textSize="18sp" /> </RelativeLayout> <TextView android:id="@+id/lisi_textiview" android:layout_width="fill_parent" android:layout_height="1dip" android:background="#517688" android:gravity="center" android:text="历史记录1\n历史记录2\n历史记录3\n历史记录4\n历史记录5\n历史记录6\n历史记录7\n历史记录8\n历史记录9\n历史记录10" /> <com.myrollerscrollview.view.MyScrollView android:id="@+id/main_scrollview" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:scrollbars="vertical" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#7d7d7d" android:focusable="true" android:orientation="vertical" > <TextView android:id="@+id/main_textiview" android:layout_width="fill_parent" android:layout_height="40dip" android:background="#aabbcc" android:gravity="center" android:text="这里是彩期显示区域" android:textColor="#222222" android:visibility="visible" /> <TextView android:id="@+id/main_textiview1" android:layout_width="fill_parent" android:layout_height="550dip" android:background="#cbacba" android:gravity="center" android:text="这里是选球界面,红球" android:textColor="#d80702" android:visibility="visible" /> <TextView android:id="@+id/main_textiview2" android:layout_width="fill_parent" android:layout_height="550dip" android:background="#abcabc" android:gravity="center" android:text="这里是选球界面,篮球" android:textColor="#0000ff" android:visibility="visible" /> </LinearLayout> </com.myrollerscrollview.view.MyScrollView> <!-- 金额,确认选号 --> <View android:layout_width="fill_parent" android:layout_height="1px" android:background="#dedede" /> <RelativeLayout android:layout_width="fill_parent" android:layout_height="52dip" android:background="#f8f8f8" android:orientation="horizontal" > <TextView android:id="@+id/ssq_main_txt_mainConfirm" android:layout_width="80dp" android:layout_height="36dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="10dp" android:gravity="center" android:text="投注" android:textColor="#222222" android:textSize="16sp" android:textStyle="bold" android:typeface="monospace" /> </RelativeLayout> </LinearLayout>
主类Activity代码很简单:
package com.myrollerscrollview.activity; import android.app.Activity; import android.os.Bundle; import android.view.Window; import android.widget.TextView; import com.myrollerscrollview.R; import com.myrollerscrollview.listener.MyScrollViewListener; import com.myrollerscrollview.view.MyScrollView; //主界面 public class MainActivity extends Activity implements MyScrollViewListener { private MyScrollView scrllon_view; private TextView lisi_textview; private TextView main_textview; private TextView main_textview1; private TextView main_textview2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏 setContentView(R.layout.activity_main); scrllon_view = (MyScrollView) findViewById(R.id.main_scrollview); lisi_textview = (TextView) findViewById(R.id.lisi_textiview); main_textview = (TextView) findViewById(R.id.main_textiview); main_textview1 = (TextView) findViewById(R.id.main_textiview1); main_textview2 = (TextView) findViewById(R.id.main_textiview2); scrllon_view.setMaxHeight(350); scrllon_view.topView = this.lisi_textview; } @Override public void onScrollChanged(MyScrollView scrollView, int x, int y, int oldx, int oldy) { //System.out.println("x=" + x + " y=" + y + " oldx=" + oldx + " oldy=" + oldy); } }
重点是这里 自定义的Scrollview
package com.myrollerscrollview.view; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.ScrollView; import com.myrollerscrollview.listener.MyScrollViewListener; /** * 自定卷帘Scrollview * * @author lengguoxing * * 引用地址:com.myrollerscrollview.view.MyScrollView */ public class MyScrollView extends ScrollView { private MyScrollViewListener scrollViewListener = null; private MyScrollView myScrollView = this; public View topView;//顶部卷帘 public boolean isTopViewAllGone = true;//卷帘完全隐藏 private int downMoveDistance = 0;// 向下滑动的距离 private int upMoveDistance = 0;// 滑动到底时,向上滑动的距离 public int maxHeight = 100;//这个是可以用户通过方法setMaxHeight自定义的 public MyScrollView(Context context) { super(context); } public MyScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MyScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public void setScrollViewListener(MyScrollViewListener scrollViewListener) { this.scrollViewListener = scrollViewListener; } public int getMaxHeight() { return maxHeight; } public void setMaxHeight(int maxHeight) { this.maxHeight = maxHeight; } @Override protected void onScrollChanged(int x, int y, int oldx, int oldy) { super.onScrollChanged(x, y, oldx, oldy); if (scrollViewListener != null ) { scrollViewListener.onScrollChanged(this, x, y, oldx, oldy); } } int downY = 0;// 按下时候焦点的y坐标 int moveY = 0;// 滑动时候存储焦点的y坐标 int upY = 0;// 释放时候焦点的y坐标 int downScrollY = 0;//滑动开始时滚动条的Y坐标 android.widget.LinearLayout.LayoutParams lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.MATCH_PARENT, 0); /** * * topView.getBottom() - topView.getTop() == maxHeight 卷帘完全显示的判断 * topView.getBottom() == topView.getTop() 卷帘完全隐藏的判断 * myScrollView.getScrollY()==0可以判断是否滚动了。 */ @Override public boolean onTouchEvent(MotionEvent event) { //System.out.println("onTouchEvent----------------------getHeight=" + this.getHeight() + " "); switch (event.getAction()) { case MotionEvent.ACTION_DOWN://按下的时候 //System.out.println("----------------action down=(" + event.getX() +", " + event.getY() + ")"); downY = (int) event.getY(); downScrollY = myScrollView.getScrollY(); //upMoveDistance = downMoveDistance; upMoveDistance = 0; return super.onTouchEvent(event); case MotionEvent.ACTION_MOVE://滑动的时候 //System.out.println("----------------action move=(" + event.getX() +", " + event.getY() + ")"); //System.out.println("----------------myScrollView " + myScrollView.getTop() + " " + myScrollView.getBottom()); //System.out.println("---------------------topView " + topView.getTop() + " " + topView.getBottom()); //System.out.println("-----myScrollView.getScrollY " + myScrollView.getScrollY() + " maxheight=" + maxHeight); //System.out.println("-----------------downMoveDistance= " + downMoveDistance + " upMoveDistance=" + upMoveDistance); if(topView.getBottom() - topView.getTop() == maxHeight){//卷帘完全显示 downMoveDistance = maxHeight; upMoveDistance = 0; } if(topView.getBottom() == topView.getTop()){//卷帘完全隐藏 isTopViewAllGone = true; downMoveDistance = 0; upMoveDistance = maxHeight; }else{ isTopViewAllGone = false; } moveY = (int) event.getY(); int YY = moveY - downY; if (YY > 0) {// 向下滑动 int tempMove = (moveY - downY) % maxHeight; if (tempMove > downMoveDistance) { downMoveDistance = tempMove; } if (downMoveDistance > 0) { //向下滑的条件是:1、未滚动到底;2、滚动条还在顶部;3、滚动条本来就在顶部 if (downMoveDistance <= maxHeight && myScrollView.getScrollY() == 0 && downScrollY == 0) { lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.FILL_PARENT, downMoveDistance); lp.setMargins(0, 0, 0, 0); topView.setPadding(0, 0, 0, 0); topView.setLayoutParams(lp); } } } else if (YY < 0 && downMoveDistance > 0) {// 向上滑动 //这里的逻辑有点问题 int tempMove = (downY - moveY) % maxHeight; if (tempMove > upMoveDistance) { // 这里有问题 upMoveDistance = tempMove; } if (upMoveDistance > 0) { if (upMoveDistance < maxHeight && myScrollView.getScrollY() == 0) { lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.FILL_PARENT, downMoveDistance - upMoveDistance); lp.setMargins(0, 0, 0, 0); topView.setPadding(0, 0, 0, 0); topView.setLayoutParams(lp); } } } if(isTopViewAllGone){ return super.onTouchEvent(event); }else{ return false; } case MotionEvent.ACTION_UP: //System.out.println("----------------action up=(" + event.getX() +", " + event.getY() + ")"); upY = (int) event.getY(); int YY2 = (upY - downY); if (YY2 > 0) {// 向下滑动 if (YY2 < maxHeight / 2 && myScrollView.getScrollY() == 0 && downScrollY == 0) {// 滑动距离小于一半,自动弹回原处 lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.FILL_PARENT, 0); topView.setLayoutParams(lp); downMoveDistance = 0; } else if (YY2 >= maxHeight / 2 && myScrollView.getScrollY() == 0 && downScrollY == 0) {// 滑动距离大于一半,加速最底部 lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.FILL_PARENT, maxHeight); topView.setLayoutParams(lp); downMoveDistance = maxHeight; } } else if (YY2 < 0) {// 向上滑动 YY2 = -YY2;// if (YY2 < maxHeight / 2 && myScrollView.getScrollY() == 0) {// 向上滑动距离小于一半,自动弹回最底部 lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.FILL_PARENT, maxHeight); topView.setLayoutParams(lp); downMoveDistance = maxHeight; upMoveDistance = 0; } else if (YY2 >= maxHeight / 2 && myScrollView.getScrollY() == 0) {// 向上滑动距离大于一半,加速原处 lp = new android.widget.LinearLayout.LayoutParams(android.widget.LinearLayout.LayoutParams.FILL_PARENT, 0); topView.setLayoutParams(lp); downMoveDistance = 0; upMoveDistance = maxHeight; } } return super.onTouchEvent(event); } return super.onTouchEvent(event); } }
核心代码就在那个onTouchEvent方法里面
MotionEvent.ACTION_MOVE 控制滑动效果
MotionEvent.ACTION_UP 控制弹性效果
这里的几个判断很重要:
topView.getBottom() - topView.getTop() == maxHeight 卷帘完全显示的判断
topView.getBottom() == topView.getTop() 卷帘完全隐藏的判断
myScrollView.getScrollY()==0可以判断是否滚动了。
里面的注释很详细,就不一一介绍了。这里附上下载的地址 点击打开链接
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。