• Android自定义控件——有弹性的ListView,ScrollView


    上一次我们试验了有弹性的ScrollView。详情

    这一次,我们来试验有弹性的ScrollView。

    国际惯例,效果图:



    主要代码:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. import android.content.Context;  
    2. import android.graphics.Rect;  
    3. import android.util.AttributeSet;  
    4. import android.view.MotionEvent;  
    5. import android.view.animation.Animation;  
    6. import android.view.animation.Animation.AnimationListener;  
    7. import android.view.animation.TranslateAnimation;  
    8. import android.widget.AbsListView;  
    9. import android.widget.ListView;  
    10.   
    11. /** 
    12.  * ElasticScrollView有弹性的ListView 
    13.  */  
    14. public class ElasticListView extends ListView {  
    15.     private float y;  
    16.     private Rect normal = new Rect();  
    17.     private boolean animationFinish = true;  
    18.   
    19.     public ElasticListView(Context context) {  
    20.         super(context);  
    21.         init();  
    22.     }  
    23.   
    24.     public ElasticListView(Context context, AttributeSet attrs) {  
    25.         super(context, attrs);  
    26.         init();  
    27.     }  
    28.   
    29.     protected void onScrollChanged(int l, int t, int oldl, int oldt) {  
    30.   
    31.     }  
    32.   
    33.     boolean overScrolled = false;  
    34.     private void init() {  
    35.         setOnScrollListener(new OnScrollListener() {  
    36.             @Override  
    37.             public void onScrollStateChanged(AbsListView view, int scrollState) {  
    38.             }  
    39.   
    40.             @Override  
    41.             public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {  
    42.                 overScrolled = false;  
    43.             }  
    44.         });  
    45.     }  
    46.       
    47.     @Override  
    48.     protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {  
    49.         overScrolled = true;  
    50.     }  
    51.   
    52.     @Override  
    53.     public boolean onTouchEvent(MotionEvent ev) {  
    54.         commOnTouchEvent(ev);  
    55.         return super.onTouchEvent(ev);  
    56.     }  
    57.   
    58.     public void commOnTouchEvent(MotionEvent ev) {  
    59.         if (animationFinish) {  
    60.             int action = ev.getAction();  
    61.             switch (action) {  
    62.             case MotionEvent.ACTION_DOWN:  
    63.                 y = ev.getY();  
    64.                 break;  
    65.             case MotionEvent.ACTION_UP:  
    66.                 y = 0;  
    67.                 if (isNeedAnimation()) {  
    68.                     animation();  
    69.                 }  
    70.                 break;  
    71.             case MotionEvent.ACTION_MOVE:  
    72.                 final float preY = y == 0 ? ev.getY() : y;  
    73.                 float nowY = ev.getY();  
    74.                 int deltaY = (int) (preY - nowY);  
    75.   
    76.                 y = nowY;  
    77.                 // 当滚动到最上或者最下时就不会再滚动,这时移动布局  
    78.                 if (isNeedMove(deltaY)) {  
    79.                     if (normal.isEmpty()) {  
    80.                         // 保存正常的布局位置  
    81.                         normal.set(getLeft(), getTop(), getRight(), getBottom());  
    82.                     }  
    83.                     // 移动布局  
    84.                     layout(getLeft(), getTop() - deltaY / 2, getRight(), getBottom() - deltaY / 2);  
    85.                 }  
    86.                 break;  
    87.             default:  
    88.                 break;  
    89.             }  
    90.         }  
    91.     }  
    92.   
    93.     // 开启动画移动  
    94.     public void animation() {  
    95.         // 开启移动动画  
    96.         TranslateAnimation ta = new TranslateAnimation(000, normal.top - getTop());  
    97.         ta.setDuration(200);  
    98.         ta.setAnimationListener(new AnimationListener() {  
    99.             @Override  
    100.             public void onAnimationStart(Animation animation) {  
    101.                 animationFinish = false;  
    102.   
    103.             }  
    104.   
    105.             @Override  
    106.             public void onAnimationRepeat(Animation animation) {  
    107.   
    108.             }  
    109.   
    110.             @Override  
    111.             public void onAnimationEnd(Animation animation) {  
    112.                 clearAnimation();  
    113.                 // 设置回到正常的布局位置  
    114.                 layout(normal.left, normal.top, normal.right, normal.bottom);  
    115.                 normal.setEmpty();  
    116.                 animationFinish = true;  
    117.             }  
    118.         });  
    119.         startAnimation(ta);  
    120.     }  
    121.   
    122.     // 是否需要开启动画  
    123.     public boolean isNeedAnimation() {  
    124.         return !normal.isEmpty();  
    125.     }  
    126.   
    127.     // 是否需要移动布局  
    128.     public boolean isNeedMove(float deltaY) {  
    129.         if (overScrolled && getChildCount() > 0) {  
    130.             if (getLastVisiblePosition() == getCount() - 1 && deltaY > 0) {  
    131.                 return true;  
    132.             }  
    133.             if (getFirstVisiblePosition() == 0 && deltaY < 0) {  
    134.                 return true;  
    135.             }  
    136.         }  
    137.         return false;  
    138.     }  
    139. }  

    测试代码:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
    1. public class MainActivity extends Activity {  
    2.     ElasticListView listView;  
    3.     @Override  
    4.     protected void onCreate(Bundle savedInstanceState) {  
    5.         super.onCreate(savedInstanceState);  
    6.         setContentView(R.layout.activity_main);  
    7.           
    8.         listView = (ElasticListView) findViewById(R.id.listview);  
    9.           
    10.         String[] listValues = new String[20];  
    11.         for (int i=0;i<listValues.length;i++) {  
    12.             listValues[i] = "TextView" + i;  
    13.         }  
    14.         listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listValues));  
    15.     }  
    16. }  

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
    1. public class MainActivity extends Activity {  
    2.     ElasticListView listView;  
    3.     @Override  
    4.     protected void onCreate(Bundle savedInstanceState) {  
    5.         super.onCreate(savedInstanceState);  
    6.         setContentView(R.layout.activity_main);  
    7.           
    8.         listView = (ElasticListView) findViewById(R.id.listview);  
    9.           
    10.         String[] listValues = new String[20];  
    11.         for (int i=0;i<listValues.length;i++) {  
    12.             listValues[i] = "TextView" + i;  
    13.         }  
    14.         listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listValues));  
    15.     }  
    16. }  
    public class FlexibleScrollView extends ScrollView {  
      
        private Context mContext;  
        private static int mMaxOverDistance = 50;  
      
        public FlexibleScrollView(Context context, AttributeSet attrs,  
                int defStyleAttr) {  
            super(context, attrs, defStyleAttr);  
            this.mContext = context;  
            initView();  
        }  
      
        public FlexibleScrollView(Context context, AttributeSet attrs) {  
            super(context, attrs);  
            this.mContext = context;  
            initView();  
        }  
      
        public FlexibleScrollView(Context context) {  
            super(context);  
            this.mContext = context;  
            initView();  
        }  
      
        private void initView() {  
            DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();  
            float density = metrics.density;  
            mMaxOverDistance = (int) (density * mMaxOverDistance);  
        }  
      
        @Override  
        protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,  
                int scrollY, int scrollRangeX, int scrollRangeY,  
                int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {  
            return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,  
                    scrollRangeX, scrollRangeY, maxOverScrollX, mMaxOverDistance,  
                    isTouchEvent);  
        }  
    }  
    通过上面这个类也可以实现弹性效果

    二、仿朋友圈背景图片下拉

    public class ScrollDampView extends ScrollView {
    	/** 该属性具体参数 怎么控制 未解!!!! */
    	private static final int LEN = 0xc8;
    	/** 回弹时所用的时间 */
    	private static final int DURATION = 200;
    	/** 最大Y坐标 其值一般设定为Scroller对应控件的高度 */
    	private static final int MAX_DY = 200;
    
    	private Scroller mScroller;
    	/** 阻尼系数 */
    	private static final float OFFSET_RADIO = 2.5f;
    
    	private float startY;
    	private int imageViewH;
    
    	private ImageView imageView;
    	private boolean scrollerType;
    
    	public ScrollDampView(Context context, AttributeSet attrs, int defStyle) {
    		super(context, attrs, defStyle);
    
    	}
    
    	public ScrollDampView(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		mScroller = new Scroller(context);
    	}
    
    	public ScrollDampView(Context context) {
    		super(context);
    
    	}
    
    	public void setImageView(ImageView imageView) {
    		this.imageView = imageView;
    	}
    
    	float curY;
    
    	@Override
    	public boolean dispatchTouchEvent(MotionEvent event) {
    		int action = event.getAction();
    		if (!mScroller.isFinished()) {
    			return super.onTouchEvent(event);
    		}
    		switch (action) {
    		case MotionEvent.ACTION_DOWN:// 变量赋初始值
    			imageViewH = imageView.getHeight();
    			startY = event.getY();
    			break;
    		case MotionEvent.ACTION_MOVE:
    			if (imageView.isShown()) {
    				float deltaY = (event.getY() - startY ) / OFFSET_RADIO;
    				Log.i("syso", "deltaY: "+deltaY+" imageTop: "+imageView.getTop());
    				//往下拉
    				if (deltaY > 0 && deltaY <= imageView.getBottom() + LEN) {
    					android.view.ViewGroup.LayoutParams params = imageView.getLayoutParams();
    					params.height = (int) (imageViewH + deltaY);// 改变高度
    					imageView.setLayoutParams(params);
    				}
    				scrollerType = false;
    			}
    			break;
    		case MotionEvent.ACTION_UP:
    			scrollerType = true;
    			// 开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位
    			// ,即到达坐标为(startX+dx , startY+dy)处
    			mScroller.startScroll(imageView.getLeft(), imageView.getBottom(),
    					0 - imageView.getLeft(),
    					imageViewH - imageView.getBottom(), DURATION);
    			invalidate();
    			break;
    		}
    
    		return super.dispatchTouchEvent(event);
    	}
    
    	// //该mScroller针对于imageView的变化
    	// 被父视图调用,用于必要时候对其子视图的值(mScrollX和mScrollY)
    	// 进行更新。典型的情况如:父视图中某个子视图使用一个Scroller对象来实现滚动操作,会使得此方法被调用。
    	@Override
    	public void computeScroll() {
    		if (mScroller.computeScrollOffset()) {
    			int x = mScroller.getCurrX();
    			int y = mScroller.getCurrY();// ImageView的当前Y坐标
    			imageView.layout(0, 0, x + imageView.getWidth(), y);// 使imageView本身做相应变化
    			invalidate();
    			// 滑动还未完成时,手指抬起时,当前y坐标大于其实imageView的高度时
    			// 设定imageView的布局参数 作用:使除imageView之外的控件做相应变化
    			if (!mScroller.isFinished() && scrollerType && y > MAX_DY) {
    				android.view.ViewGroup.LayoutParams params = imageView
    						.getLayoutParams();
    				params.height = y;
    				imageView.setLayoutParams(params);
    			}
    		}
    	}
    
    }
    

    布局文件:

    <com.example.dampview.ScrollDampView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/dampview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical" >
    
            <!--此处必须设置imageview的scaleType为centerCrop,当然在代码中设置也可以-->
            <ImageView
                android:id="@+id/img"
                android:layout_width="match_parent"
                android:layout_height="160dp"
                android:scaleType="centerCrop"
                android:src="@drawable/image" />
    
            <ImageView
                android:id="@+id/iv_photo"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginTop="-32dp"
                android:src="@drawable/ic_launcher" 
                />
    
        </LinearLayout>
    
    </com.example.dampview.ScrollDampView>


  • 相关阅读:
    python网络爬虫与信息提取——5.信息组织与提取方法
    python网络爬虫与信息提取——4.Beautiful Soup库入门
    python网络爬虫与信息提取——3.requests爬虫实战
    python网络爬虫与信息提取——2.网络爬虫排除标准robots
    python网络爬虫与信息提取——1.requests库入门
    时间戳转日期
    splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目
    数组、对象等的按值传递与数字、字符串不同
    用flex做垂直居中
    手机端页面自适应解决方案-rem布局
  • 原文地址:https://www.cnblogs.com/lbangel/p/4335879.html
Copyright © 2020-2023  润新知