安卓自定义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可以判断是否滚动了。

里面的注释很详细,就不一一介绍了。这里附上下载的地址  点击打开链接

时间: 2024-11-05 18:51:55

安卓自定义Scrollview,实现卷帘效果的相关文章

Android 自定义ScrollView(具有反弹效果的ScrollView,能够兼容横向的滑动)

package com.itau.jingdong.widgets; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.TranslateAnimation; import and

android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变

首先要知道  自定义scrollview 仿QQ效果 下拉伸缩放大顶部图片 的原理是监听ontouch事件,在MotionEvent.ACTION_MOVE事件时候,使用不同倍数的系数,重置布局位置[注此处是伸缩隐藏,不是同比例放大] inner.layout(normal.left, (int) (normal.top + inner_move_H), normal.right, (int) (normal.bottom + inner_move_H)); 关于“自定义scrollview 仿

Android -- 自定义ScrollView实现放大回弹效果

1,刚刚在别人开源的项目中看到了一个挺不错的用户体验,效果图如下: 2,那下面我们就来实现一下,首先看一下布局,由于一般只是我们包含头像的那部分方法,所以这里我们要把布局分成两部分,对应的布局文件效果图如下: 3,自定义ScrollView 第一步:创建一个类,继承自ScrollView,重写相应的构造函数 public class ZoomInScrollView extends ScrollView { public ZoomInScrollView(Context context) { t

安卓 搭建带有多种监听自定义ScrollView

=== 搭建带有多种监听自定义ScrollView === 虽然安卓5.1已经release, 但是ScrollView的封装和对外API依旧少的可怜, 虽然它优化得很好了. 所以问题来了: ScrollView滑动方向是什么, 何时停止? 所以本文的目标出现了: 解决这些看似小, 但是用起来却很燃眉的问题! 首先思考: 如何知道ScrollView是否在滚动, 不过这一点请放心, SDK还是提供了这个功能, 不然SDK也太烂了. 呵呵, 找打了, 首先请继承ScrollView这个父类, 毕竟

ios:仿照安卓小米商城head左右滚动效果(多屏滚动)

1.之前做的应用需要这个效果但是当时用的比较复杂(绘图)的方法来实现,现在想到了一个新的方法. 2.用到了http://www.cnblogs.com/yoon/p/3616503.html 里面的小技巧 3.思路: 主要是在新的scrollview中重写Layoutsubviews 代码如下: - (void)layoutSubviews { [super layoutSubviews]; for (UIView *view in self.subviews) { if (view.tag =

Android 自定义ScrollView ListView 体验各种纵向滑动的需求

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38950509,本文出自[张鸿洋的博客] 1.概述 群里的一个哥们有个需求是这样的:问题:主要功能就是:1.循环的一个滑动:2.每次滑动结束,保持每个Item的完整.然后我当时给他写了个Demo,所有代码都在Activity里面,后期看来其太恶心了,修改也不方便:貌似那哥们还因为那代码修改到12点,大大的赞一下这哥们的毅力,也深表歉意,今天特意把代码抽取成自定义的ScrollVi

安卓自定义日历控件

尊重作者劳动成果,转载请注明出处:http://blog.csdn.net/baiyuliang2013/article/details/37732149 最近,因工作需要,需要实现自定义日历控件功能,主要应用于软件中的酒店入住时间选择功能,进入日历后,可选择入住时间,及离开时间,选择完成后,再次进入日历时,会显示上次选中的结果,默认选择日期是在距当前日期三个月内,三个月以外的均以灰色显示,且不可点击.本篇实现的效果是高仿某软件的界面效果: 某软件界面效果: 本篇实现的效果: 另外,对于日期选择

【2014年最后的分享啦】Android实现自定义刮刮卡效果View

一.简介: 今天是2014年最后一天啦,首先在这里,我祝福大家在新的2015年都一个个的新健康,新收入,新顺利,新如意!!! 上一偏,我介绍了用Xfermode实现自定义圆角和椭圆图片view的博文<Android实现自定义圆形.圆角和椭圆ImageView(使用Xfermode图形渲染方法)>, 今天我们来看看如何实现电商app里常用到的刮刮卡效果的view组件,其实原理和实现圆角图片的差不多,都是使用Xfermode渲染模式来实现的. (老规矩,源码在博文最后给出哈) 基本原理步骤是这样的

Cocos2dx 小技巧(十四)ScrollView实现缩放效果

这阶段心绪比較乱,所以这篇开头就不扯淡了.(谁说大姨夫来了我跟谁急!~~)说到大姨夫我突然想到英雄联盟有个美女讲解叫伊芙蕾亚,她的堂弟ID居然叫:姨夫累呀,好笑吧(呵呵,有点冷~~额,我都说不扯淡了).------------前天有个网友问我一些关于scrollView的使用方法,因为在QQ上实在讲不清,所以就利用晚上的时间写这篇博客出来了.本篇要实现的功能是用scrollView 拖动对象时,对象移动到某个固定范围会有放大.缩小的效果.以下開始.在进入正题前我先简短的介绍下scrollView