android 有弹性的ScrollView 简单实现,与处理ScrollView和ListView,GridView之间的冲突

处理ScrollView和ListView,GridView之间的冲突,

最好的办法就是继承这两个类,重写他们的onMeasure方法即可:

ListView:

import android.widget.ListView;

/**
 * ScrollView中嵌入ListView,让ListView全显示出来
 * @author John
 *
 */
public class MyListView extends ListView{

    public MyListView(android.content.Context context,android.util.AttributeSet attrs){
        super(context, attrs);
    }

    /**
     * 设置不滚动
     */
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);

    }

}

GridView:

import android.widget.GridView;

public class MyGridView extends GridView {
    public MyGridView(android.content.Context context,
            android.util.AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * 设置不滚动
     */
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);

    }

}

如果是ListView中嵌套GridView也可以用这个办法。简单实用的处理了这个冲突。

下面是重写ScrollView,实现有弹性的ScrollView

/**
* 有弹性的ScrollView
* 实现下拉弹回和上拉弹回
* @author John
*/
public class OwnScroview extends ScrollView {

   private static final String TAG = "ElasticScrollView";

   //移动因子, 是一个百分比, 比如手指移动了100px, 那么View就只移动20px
   //目的是达到一个延迟的效果
   private static final float MOVE_FACTOR = 0.4f;

   //松开手指后, 界面回到正常位置需要的动画时间
   private static final int ANIM_TIME = 300;

   //ScrollView的子View, 也是ScrollView的唯一一个子View
   private View contentView; 

   //手指按下时的Y值, 用于在移动时计算移动距离
   //如果按下时不能上拉和下拉, 会在手指移动时更新为当前手指的Y值
   private float startY;

   //用于记录正常的布局位置
   private Rect originalRect = new Rect();

   //手指按下时记录是否可以继续下拉
   private boolean canPullDown = false;

   //手指按下时记录是否可以继续上拉
   private boolean canPullUp = false;

   //在手指滑动的过程中记录是否移动了布局
   private boolean isMoved = false;

   public OwnScroview(Context context) {
       super(context);
   }

   public OwnScroview(Context context, AttributeSet attrs) {
       super(context, attrs);
   }

   @Override
   protected void onFinishInflate() {
       if (getChildCount() > 0) {
           contentView = getChildAt(0);
       }
   }

   @Override
   protected void onLayout(boolean changed, int l, int t, int r, int b) {
       super.onLayout(changed, l, t, r, b);

       if(contentView == null) return;

       //ScrollView中的唯一子控件的位置信息, 这个位置信息在整个控件的生命周期中保持不变
       originalRect.set(contentView.getLeft(), contentView.getTop(), contentView
               .getRight(), contentView.getBottom());
   }

   /**
    * 在触摸事件中, 处理上拉和下拉的逻辑
    */
   @Override
   public boolean dispatchTouchEvent(MotionEvent ev) {

       if (contentView == null) {
           return super.dispatchTouchEvent(ev);
       }

       int action = ev.getAction();

       switch (action) {
       case MotionEvent.ACTION_DOWN:

           //判断是否可以上拉和下拉
           canPullDown = isCanPullDown();
           canPullUp = isCanPullUp();

           //记录按下时的Y值
           startY = ev.getY();
           break;

       case MotionEvent.ACTION_UP:

           if(!isMoved) break;  //如果没有移动布局, 则跳过执行

           // 开启动画
           TranslateAnimation anim = new TranslateAnimation(0, 0, contentView.getTop(),
                   originalRect.top);
           anim.setDuration(ANIM_TIME);

           contentView.startAnimation(anim);

           // 设置回到正常的布局位置
           contentView.layout(originalRect.left, originalRect.top,
                   originalRect.right, originalRect.bottom);

           //将标志位设回false
           canPullDown = false;
           canPullUp = false;
           isMoved = false;

           break;
       case MotionEvent.ACTION_MOVE:

           //在移动的过程中, 既没有滚动到可以上拉的程度, 也没有滚动到可以下拉的程度
           if(!canPullDown && !canPullUp) {
               startY = ev.getY();
               canPullDown = isCanPullDown();
               canPullUp = isCanPullUp();

               break;
           }

           //计算手指移动的距离
           float nowY = ev.getY();
           int deltaY = (int) (nowY - startY);

           //是否应该移动布局
           boolean shouldMove =
                   (canPullDown && deltaY > 0)    //可以下拉, 并且手指向下移动
                   || (canPullUp && deltaY< 0)    //可以上拉, 并且手指向上移动
                   || (canPullUp && canPullDown); //既可以上拉也可以下拉(这种情况出现在ScrollView包裹的控件比ScrollView还小)

           if(shouldMove){
               //计算偏移量
               int offset = (int)(deltaY * MOVE_FACTOR);

               //随着手指的移动而移动布局
               contentView.layout(originalRect.left, originalRect.top + offset,
                       originalRect.right, originalRect.bottom + offset);

               isMoved = true;  //记录移动了布局
           }

           break;
       default:
           break;
       }

       return super.dispatchTouchEvent(ev);
   }

   /**
    * 判断是否滚动到顶部
    */
   private boolean isCanPullDown() {
       return getScrollY() == 0 ||
               contentView.getHeight() < getHeight() + getScrollY();
   }

   /**
    * 判断是否滚动到底部
    */
   private boolean isCanPullUp() {
       return  contentView.getHeight() <= getHeight() + getScrollY();
   }

}

然后再xml中用上就行了。

时间: 2024-08-24 08:11:12

android 有弹性的ScrollView 简单实现,与处理ScrollView和ListView,GridView之间的冲突的相关文章

ScrollView listView gridView 之间的冲突问题

在ScrollView中的listView gridView添加适配器之后添加//设置gridView整体的高度 public void setListViewHeightBasedOnChildren(GridView gridView) { // 获取ListView对应的Adapter if(adapter== null) { return; } int totalHeight = 0; for(int i = 0, len = adapter.getCount(); i < len; i

Android自定义弹性ScrollView

Android自定义弹性ScrollView 总结了下最近写的弹性ScrollView,如下代码主要是通过触摸事件加动态更改布局实现的弹性ScrollView,具体分析都在注解中! package ljh.android.view; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; impo

Android ScrollView嵌套HorizontalScrollView 滑动问题 ScrollView包含GridView显示问题

今天项目使用到ScrollView嵌套HorizontalScrollView,ScrollView里包含GridView,发现几个问题很经典,在此记录: 问题1.ScrollView嵌套HorizontalScrollView跳变问题,ScrollView.HorizontalScrollView自动下拉到最后一行: 设置到初始坐标(0,0)解决方法: (时机:数据解析完并且刷新notifyDataSetChanged()之后进行下面代码设置) scrollview.smoothScrollT

Android ExpandableListView 带有Checkbox的简单应用

expandablelistview2_groups.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height=&qu

Android中接口(Interface)的简单使用

  Android中接口(Interface)的简单使用 Java中的接口可以被看作是只包含常量和抽象方法的抽象类 . 可以使用如下方式定义一个接口: public interface InterfaceDemo { int i = 10; void method1(); int method2(); } 使用1: 解决“多重继承”的问题 Java语言本身是不支持类的多重继承(多重继承是指一个类从多个类继承而来,即一个类拥有多个超类)的,但一个类却可以实现多个接口.这样,我们可以将一些抽象方法定

android异步类AsyncTask的简单使用

Android为了降低这个开发难度,提供了AsyncTask.AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务,更通俗地说就是一个执行后台任务的线程 而且他还会自动通知主线程更新UI 优点: 结构清晰,容易理解. 缺点 代码量稍大 下面直接看代码 1 private class AsyncLogin extends AsyncTask<Void,Integer,Boolean>{ 2 private EditText passwordEdit; 3 private EditT

Android 设计随便说说之简单实践(合理组合)

上一篇(Android 设计随便说说之简单实践(模块划分))例举了应用商店设计来说明怎么做模块划分.模块划分主要依赖于第一是业务需求,具体是怎么样的业务.应用商店则包括两个业务,就是向用户展示applist,和下载app.第二是运行环境,在Android平台,有androidsdk提供socket等API支持.因此将模块大体换发了5个模块.(当然了图片加载可以额外提出,用开源组件去做,但是这里为了说明如何设计,暂不提到.还有下载也可以利用开源组件)分别是如下: 模块1 UI模块,负责展示信息和用

Xamarin.Android之引导页的简单制作

0x01 前言 对于现在大部分的APP,第一次打开刚安装或更新安装的APP都会有几个引导界面,通常这几个引导页是告诉用户 APP有些什么功能或者修改了什么bug.新增了什么功能等等等. 下面就用Xamarin.Android来简单实现一下.主要用到的是ViewPager,当然也就离不开Xamarin.Android.Support.v4 如果遇到不能编译的问题,可以参考Xamarin.Android之简单的抽屉布局的出错处理方案. 0x02 页面布局编写 新建一个Android项目 添加几个简单

Android自定义用户控件简单范例(一)

一款优秀的移动应用需要具有自己独特统一的风格,通常情况下UI设计师会根据产品需求和使用人群的特点,设计整体的风格,界面的元素和控件的互效果.而原生态的Android控件为开发人员提供的是最基本的积木元素,如果要准确地传递统一的视觉效果和交互体验,对控件的自定义使用是非常有必要的. 这篇文章通过一个简单的从Java后台程序中进行创建的示例来说明Android自定义控件的运行原理. <LinearLayout xmlns:android="http://schemas.android.com/