博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android瀑布流的实现
阅读量:6554 次
发布时间:2019-06-24

本文共 7718 字,大约阅读时间需要 25 分钟。

hot3.png

    最近在学习android的ViewGroup,然后就想弄个例子练练手。看到网上的瀑布流挺有意思的,就尝试着去做。弄了一天终于弄好。

    android的自定义ViewGroup不多说,继承ViewGroup并覆写onLayout和onMeasure方法。在onLayout方法中设置child的布局位置,在onMeasure中测量child的宽高。以下是瀑布流的实现代码:(WaterFall写成WaterFlow,  = =!....)

package com.example.waterflowdemo;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.GestureDetector;import android.view.GestureDetector.OnGestureListener;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.Toast;public class WaterFlow extends ViewGroup implements View.OnClickListener, OnGestureListener {		private static final String TAG = WaterFlow.class.getSimpleName();		private static final int MARGIN = 2;		private Context context;		private GestureDetector gestureDetector;		/*	 * this view group's height	 */	private int viewGroupHeight = 0;		/*	 * position needed to scroll	 */	private float position = 0;		/*	 * last down position	 */	private float downPosition = 0;		private static final int COLUMNS = 2;		public WaterFlow(Context context) {		super(context);		Log.d(TAG, "WaterFlow constructor");		this.context = context;		init();	}	public WaterFlow(Context context, AttributeSet attrs) {		super(context, attrs);		Log.d(TAG, "WaterFlow constructor");		this.context = context;		init();	}		private void init() {		gestureDetector = new GestureDetector(context, this);	}	@Override	protected void onLayout(boolean changed, int l, int t, int r, int b) {		Log.d(TAG, "WaterFlow.onLayout()");		final int width = r - l;		final int height = b - t;				final int childCount = getChildCount();				int y1 = t;		int y2 = t;				for(int i = 0; i < childCount; i ++) {			final View child = getChildAt(i);			child.setTag(i);			child.setOnClickListener(this);			final int childWidth = child.getMeasuredWidth();			final int childHeight = child.getMeasuredHeight();//			Log.d(TAG, "childWidth: " + childWidth + ", childHeight: " + childHeight);			double scale = ((double)childWidth) / (width / COLUMNS);//			Log.d(TAG, "scale: " + scale);			final int w = width / COLUMNS;			int h = 0;			if(scale != 0) {				h = (int) (childHeight / scale);			} else {				h = childHeight;			}//			Log.d(TAG, "w: " + w + ", h: " + h);			if(y1 <= y2) {				child.layout(l + MARGIN, y1 + MARGIN, l + w - MARGIN, y1 + h - MARGIN);				y1 += h;//				Log.d(TAG, "y1: " + y1);			} else {				child.layout(l + w + MARGIN, y2 + MARGIN, r - MARGIN, y2 + h - MARGIN);				y2 += h;//				Log.d(TAG, "y2: " + y2);			}		}		viewGroupHeight = y1 > y2 ? y1 : y2;		Log.d(TAG, "ViewGroupHeight: " + viewGroupHeight);	}	@Override	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {		Log.d(TAG, "WaterFlow.onMeasure()");		final int childCount = getChildCount();		int arg0 = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);		int arg1 = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED);		for(int i = 0; i < childCount; i ++) {			View child = getChildAt(i);			if(child.getVisibility() != View.GONE) {				child.measure(arg0, arg1);			}		}		super.onMeasure(widthMeasureSpec, heightMeasureSpec);	}	@Override	public boolean onTouchEvent(MotionEvent event) {		int height = getMeasuredHeight();		if(viewGroupHeight <= height) {			return false;		}		switch(event.getAction()) {		case MotionEvent.ACTION_DOWN:			downPosition = event.getRawY();			break;		case MotionEvent.ACTION_MOVE:			float transLength = event.getRawY() - downPosition;			Log.d(TAG, "trans: " + transLength);			if(transLength != 0) {				position -= transLength;				if(position < 0) {					position = 0;				} else if(position > viewGroupHeight - height) {					position = viewGroupHeight - height;				}				Log.d(TAG, "position: " + position);				this.scrollTo(0, (int) position);			}			downPosition = event.getRawY();			break;			default:		}		return gestureDetector.onTouchEvent(event);	}	@Override	public boolean onInterceptTouchEvent(MotionEvent ev) {				switch(ev.getAction()) {		case MotionEvent.ACTION_DOWN:			onTouchEvent(ev);			return false;		case MotionEvent.ACTION_MOVE:			return true;		case MotionEvent.ACTION_UP:			return false;		}		return false;	}	@Override	public void onClick(View v) {		int i = (Integer) v.getTag();		Toast.makeText(context, "Number " + i, Toast.LENGTH_SHORT).show();	}	@Override	public boolean onDown(MotionEvent e) {		// TODO Auto-generated method stub		return false;	}	@Override	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,			float velocityY) {		Log.d(TAG, "onFiling");		return false;	}	@Override	public void onLongPress(MotionEvent e) {		// TODO Auto-generated method stub			}	@Override	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,			float distanceY) {		Log.d(TAG, "onScroll");		return true;	}	@Override	public void onShowPress(MotionEvent e) {		// TODO Auto-generated method stub			}	@Override	public boolean onSingleTapUp(MotionEvent e) {		// TODO Auto-generated method stub		return false;	}}

onTouchEvent处理了瀑布流的滚动。如果做效果好一点可以添加手势操作,在onFiling中加入快速滑动等。可以在onTouchEvent中将MotionEvent交由GestureDetector处理。onClick响应了子view的点击事件,在这里只是简单地弹出一个toast并标注是第几个。

解决onTouch和onClick的冲突
昨天在网上看个一哥们的博文,看到了android关于onClick、onLongClick和onTouch的机制,在此多谢那位兄弟了。onClick是在onTouch中的MotionEvent.ACTION_DWON和MotionEvent.ACTION_UP中处理,在UP中会判断touch位置是否改变,touch的位置是否还在同一个view上,然后决定是否响应onClick时间;onLongClick是直接在MotionEvent.ACTION_DOWN中判断,当超过一定时间后就会响应onLongClick。所以在 onIntercepTouchEvent 中在DOWN中直接执行一次本view的onTouchEvent,然后返回false;在MOVE中返回true由本view拦截消耗事件;在UP中返回false将事件传递到子view中。
下面是测试的Activity代码,
package com.example.waterflowdemo;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.graphics.Color;import android.view.Menu;import android.view.ViewGroup;import android.widget.ImageView;public class MainActivity extends Activity {		private static final String TAG = "MainActivity";		private WaterFlow waterFlow;		private AddViewThread addViewThread;		static Handler handler = new Handler() {		private int index = 0;		@Override		public void handleMessage(Message msg) {			super.handleMessage(msg);			if(msg.what == 0 && msg.obj != null && msg.obj instanceof WaterFlow) {				WaterFlow waterFlow = (WaterFlow) msg.obj;				ImageView image = new ImageView(waterFlow.getContext());				image.setImageResource(R.drawable.d1 + (index % 22));				image.setBackgroundColor(Color.GRAY);				ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);				lp.setMargins(2, 2, 2, 2);				image.setLayoutParams(lp);				image.setTag(index);				waterFlow.addView(image);				index ++;			}		}			};		@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		waterFlow = (WaterFlow) findViewById(R.id.waterflow);		setContentView(waterFlow = (WaterFlow) findViewById(R.id.waterflow));				(addViewThread = new AddViewThread()).start();	}			@Override	protected void onDestroy() {		addViewThread.flag = false;		super.onDestroy();	}	@Override	public boolean onCreateOptionsMenu(Menu menu) {		// Inflate the menu; this adds items to the action bar if it is present.		getMenuInflater().inflate(R.menu.main, menu);		return true;	}		class AddViewThread extends Thread {				boolean flag = true;				public void run() {			while(flag) {				Message msg = handler.obtainMessage(0, waterFlow);				handler.sendMessage(msg);				try {					Thread.sleep(2000);				} catch (InterruptedException e) {					e.printStackTrace();				}			}		}	}}
最后图片过多的话,应该就会产生OOM的问题。这个就要做图片的及时回收了,这个可以参照google官方的那个Demo解决。以上就这么多了,接下来去研究研究ViewGroup和动画结合的效果了。

转载于:https://my.oschina.net/u/724985/blog/149932

你可能感兴趣的文章
上海某软件公司电话面试分享
查看>>
TCP 和 UDP 协议发送数据包的大小 (转载)
查看>>
用Alamofire进行网络请求的一段代码解析(一)
查看>>
elasticsearch的percolator操作
查看>>
windows 定时任务:schtasks,定时关闭网易云音乐
查看>>
C# Note17: 使用Ionic.Zip.dll实现解压缩文件
查看>>
Mina Basics 06-传输
查看>>
c 编译异常 switch 之a label can only be part of a statement and a declaration is not a statement...
查看>>
nullnullDataTable 排序
查看>>
Codeforces Ilya and Queries
查看>>
NEWS - InstallShield 2013发布
查看>>
Viewport
查看>>
〖Linux〗Debian 7.1.0 Wheezy使用ltib报错的解决办法
查看>>
〖Android〗(how-to) fix k860/k860i buletooth.
查看>>
static与线程安全 -摘自网络
查看>>
jsf标签,jsp标签与jstl标签
查看>>
使用PHP CURL的POST数据
查看>>
struts2:表单标签
查看>>
mysql字符串截取
查看>>
ASP.NET MVC3 通过Url传多个参数方法
查看>>