仿微信图片缩放效果以及listview反弹效果

这些效果都是基于一些前辈的基础上进行修改的,以满足自己想要的效果,在此对几位前辈表示感谢。

废话不多说了,先上效果图。



因为都是一些动画,图片可能无法看出效果,先说一下主要功能。

1.listview的动画反弹效果

2.点击图片全屏查看图片,可对图片进行双指放大缩小移动,点击屏幕图片消失,点击返回图片消失,弹出和消失时都有简单动画。

资源下载:http://download.csdn.net/detail/qiang_csd/7361673


listview的反弹通过scrollview实现,图片的查看通过popupwindow实现,需要注意的是scrollview嵌套listview时必须自定义listview重写onMeasure()方法,否则无法正确显示。

下面是主要的类:

DragImageView.java

package com.example.imitateWeChat;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;

/****
 * 这里你要明白几个方法执行的流程: 首先ImageView是继承自View的子类.
 * onLayout方法:是一个回调方法.该方法会在在View中的layout方法中执行,在执行layout方法前面会首先执行setFrame方法.
 * layout方法:
 * setFrame方法:判断我们的View是否发生变化,如果发生变化,那么将最新的l,t,r,b传递给View,然后刷新进行动态更新UI.
 * 并且返回ture.没有变化返回false.
 * 
 * invalidate方法:用于刷新当前控件,
 * 
 * 
 * 
 */
public class DragImageView extends ImageView {

	private Activity mActivity;

	private int screen_W, screen_H;// 可见屏幕的宽高度

	private int bitmap_W, bitmap_H;// 当前图片宽高

	private int MAX_W, MAX_H, MIN_W, MIN_H;// 极限值

	private int current_Top, current_Right, current_Bottom, current_Left;// 当前图片上下左右坐标

	private int start_Top = -1, start_Right = -1, start_Bottom = -1,
			start_Left = -1;// 初始化默认位置.

	private int start_x, start_y, current_x, current_y;// 触摸位置

	private float beforeLenght, afterLenght;// 两触点距离

	private float scale_temp;// 缩放比例

	/**
	 * 模式 NONE:无 DRAG:拖拽. ZOOM:缩放
	 * 
	 * @author zhangjia
	 * 
	 */
	public enum MODE {
		NONE, DRAG, ZOOM

	};

	public MODE mode = MODE.NONE;// 默认模式

	private boolean isControl_V = false;// 垂直监控

	private boolean isControl_H = false;// 水平监控

	private ScaleAnimation scaleAnimation;// 缩放动画

	public boolean isScaleAnim = false;// 缩放动画

	private MyAsyncTask myAsyncTask;// 异步动画

	private boolean isOnClick;
	private OnClickCallback onClickCallBack;

	/** 构造方法 **/
	public DragImageView(Context context) {
		super(context);
	}

	public void setmActivity(Activity mActivity) {
		this.mActivity = mActivity;
	}

	/** 可见屏幕宽度 **/
	public void setScreen_W(int screen_W) {
		this.screen_W = screen_W;
	}

	/** 可见屏幕高度 **/
	public void setScreen_H(int screen_H) {
		this.screen_H = screen_H;
	}

	public OnClickCallback getOnClickCallBack() {
		return onClickCallBack;
	}

	public void setOnClickCallBack(OnClickCallback onClickCallBack) {
		this.onClickCallBack = onClickCallBack;
	}

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

	/***
	 * 设置显示图片
	 */
	@Override
	public void setImageBitmap(Bitmap bm) {
		super.setImageBitmap(bm);
		/** 获取图片宽高 **/
		bitmap_W = bm.getWidth();
		bitmap_H = bm.getHeight();

		MAX_W = bitmap_W * 3;
		MAX_H = bitmap_H * 3;

		MIN_W = bitmap_W / 2;
		MIN_H = bitmap_H / 2;

	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		if (start_Top == -1) {
			start_Top = top;
			start_Left = left;
			start_Bottom = bottom;
			start_Right = right;
		}

	}

	/***
	 * touch 事件
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		/** 处理单点、多点触摸 **/
		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
			isOnClick = true;
			onTouchDown(event);
			break;
		// 多点触摸
		case MotionEvent.ACTION_POINTER_DOWN:
			isOnClick = false;
			onPointerDown(event);
			break;

		case MotionEvent.ACTION_MOVE:
			isOnClick = false;
			onTouchMove(event);
			break;
		case MotionEvent.ACTION_UP:
			mode = MODE.NONE;
			if (isOnClick) {
				if (onClickCallBack != null) {
					onClickCallBack.callback();
				}
			}
			break;

		// 多点松开
		case MotionEvent.ACTION_POINTER_UP:
			mode = MODE.NONE;
			/** 执行缩放还原 **/
			if (isScaleAnim) {
				doScaleAnim();
			}
			break;
		}

		return true;
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			onClickCallBack.callback();
		}
		return super.onKeyDown(keyCode, event);
	}

	/** 按下 **/
	public void onTouchDown(MotionEvent event) {
		mode = MODE.DRAG;

		current_x = (int) event.getRawX();
		current_y = (int) event.getRawY();

		start_x = (int) event.getX();
		start_y = current_y - this.getTop();

	}

	/** 两个手指 只能放大缩小 **/
	public void onPointerDown(MotionEvent event) {
		if (event.getPointerCount() == 2) {
			mode = MODE.ZOOM;
			beforeLenght = getDistance(event);// 获取两点的距离
		}
	}

	/** 移动的处理 **/
	public void onTouchMove(MotionEvent event) {
		int left = 0, top = 0, right = 0, bottom = 0;
		/** 处理拖动 **/
		if (mode == MODE.DRAG) {

			/** 在这里要进行判断处理,防止在drag时候越界 **/

			/** 获取相应的l,t,r ,b **/
			left = current_x - start_x;
			right = current_x + this.getWidth() - start_x;
			top = current_y - start_y;
			bottom = current_y - start_y + this.getHeight();

			/** 水平进行判断 **/
			if (isControl_H) {
				if (left >= 0) {
					left = 0;
					right = this.getWidth();
				}
				if (right <= screen_W) {
					left = screen_W - this.getWidth();
					right = screen_W;
				}
			} else {
				left = this.getLeft();
				right = this.getRight();
			}
			/** 垂直判断 **/
			if (isControl_V) {
				if (top >= 0) {
					top = 0;
					bottom = this.getHeight();
				}

				if (bottom <= screen_H) {
					top = screen_H - this.getHeight();
					bottom = screen_H;
				}
			} else {
				top = this.getTop();
				bottom = this.getBottom();
			}
			if (isControl_H || isControl_V)
				this.setPosition(left, top, right, bottom);

			current_x = (int) event.getRawX();
			current_y = (int) event.getRawY();

		}
		/** 处理缩放 **/
		else if (mode == MODE.ZOOM) {

			afterLenght = getDistance(event);// 获取两点的距离

			float gapLenght = afterLenght - beforeLenght;// 变化的长度

			if (Math.abs(gapLenght) > 5f) {
				scale_temp = afterLenght / beforeLenght;// 求的缩放的比例

				this.setScale(scale_temp);

				beforeLenght = afterLenght;
			}
		}

	}

	/** 获取两点的距离 **/
	float getDistance(MotionEvent event) {
		float x = event.getX(0) - event.getX(1);
		float y = event.getY(0) - event.getY(1);

		return FloatMath.sqrt(x * x + y * y);
	}

	/** 实现处理拖动 **/
	private void setPosition(int left, int top, int right, int bottom) {
		this.layout(left, top, right, bottom);
	}

	/** 处理缩放 **/
	void setScale(float scale) {
		int disX = (int) (this.getWidth() * Math.abs(1 - scale)) / 4;// 获取缩放水平距离
		int disY = (int) (this.getHeight() * Math.abs(1 - scale)) / 4;// 获取缩放垂直距离

		// 放大
		if (scale > 1 && this.getWidth() <= MAX_W) {
			current_Left = this.getLeft() - disX;
			current_Top = this.getTop() - disY;
			current_Right = this.getRight() + disX;
			current_Bottom = this.getBottom() + disY;

			this.setFrame(current_Left, current_Top, current_Right,
					current_Bottom);
			/***
			 * 此时因为考虑到对称,所以只做一遍判断就可以了。
			 */
			if (current_Top <= 0 && current_Bottom >= screen_H) {
				// Log.e("jj", "屏幕高度=" + this.getHeight());
				isControl_V = true;// 开启垂直监控
			} else {
				isControl_V = false;
			}
			if (current_Left <= 0 && current_Right >= screen_W) {
				isControl_H = true;// 开启水平监控
			} else {
				isControl_H = false;
			}

		}
		// 缩小
		else if (scale < 1 && this.getWidth() >= MIN_W) {
			current_Left = this.getLeft() + disX;
			current_Top = this.getTop() + disY;
			current_Right = this.getRight() - disX;
			current_Bottom = this.getBottom() - disY;
			/***
			 * 在这里要进行缩放处理
			 */
			// 上边越界
			if (isControl_V && current_Top > 0) {
				current_Top = 0;
				current_Bottom = this.getBottom() - 2 * disY;
				if (current_Bottom < screen_H) {
					current_Bottom = screen_H;
					isControl_V = false;// 关闭垂直监听
				}
			}
			// 下边越界
			if (isControl_V && current_Bottom < screen_H) {
				current_Bottom = screen_H;
				current_Top = this.getTop() + 2 * disY;
				if (current_Top > 0) {
					current_Top = 0;
					isControl_V = false;// 关闭垂直监听
				}
			}

			// 左边越界
			if (isControl_H && current_Left >= 0) {
				current_Left = 0;
				current_Right = this.getRight() - 2 * disX;
				if (current_Right <= screen_W) {
					current_Right = screen_W;
					isControl_H = false;// 关闭
				}
			}
			// 右边越界
			if (isControl_H && current_Right <= screen_W) {
				current_Right = screen_W;
				current_Left = this.getLeft() + 2 * disX;
				if (current_Left >= 0) {
					current_Left = 0;
					isControl_H = false;// 关闭
				}
			}

			if (isControl_H || isControl_V) {
				this.setFrame(current_Left, current_Top, current_Right,
						current_Bottom);
			} else {
				this.setFrame(current_Left, current_Top, current_Right,
						current_Bottom);
				isScaleAnim = true;// 开启缩放动画
			}

		}

	}

	/***
	 * 缩放动画处理
	 */
	public void doScaleAnim() {
		myAsyncTask = new MyAsyncTask(screen_W, this.getWidth(),
				this.getHeight());
		myAsyncTask.setLTRB(this.getLeft(), this.getTop(), this.getRight(),
				this.getBottom());
		myAsyncTask.execute();
		isScaleAnim = false;// 关闭动画
	}

	/***
	 * 回缩动画執行
	 */
	class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
		private int screen_W, current_Width, current_Height;

		private int left, top, right, bottom;

		private float scale_WH;// 宽高的比例

		/** 当前的位置属性 **/
		public void setLTRB(int left, int top, int right, int bottom) {
			this.left = left;
			this.top = top;
			this.right = right;
			this.bottom = bottom;
		}

		private float STEP = 8f;// 步伐

		private float step_H, step_V;// 水平步伐,垂直步伐

		public MyAsyncTask(int screen_W, int current_Width, int current_Height) {
			super();
			this.screen_W = screen_W;
			this.current_Width = current_Width;
			this.current_Height = current_Height;
			scale_WH = (float) current_Height / current_Width;
			step_H = STEP;
			step_V = scale_WH * STEP;
		}

		@Override
		protected Void doInBackground(Void... params) {

			while (current_Width <= bitmap_W) {

				left -= step_H;
				top -= step_V;
				right += step_H;
				bottom += step_V;

				current_Width += 2 * step_H;

				left = Math.max(left, start_Left);
				top = Math.max(top, start_Top);
				right = Math.min(right, start_Right);
				bottom = Math.min(bottom, start_Bottom);
				Log.e("jj", "top=" + top + ",bottom=" + bottom + ",left="
						+ left + ",right=" + right);
				onProgressUpdate(new Integer[] { left, top, right, bottom });
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			return null;
		}

		@Override
		protected void onProgressUpdate(final Integer... values) {
			super.onProgressUpdate(values);
			mActivity.runOnUiThread(new Runnable() {
				@Override
				public void run() {
					setFrame(values[0], values[1], values[2], values[3]);
				}
			});

		}

	}

	public interface OnClickCallback {
		public void callback();
	}
}

ReboundScrollView.java

package com.example.imitateWeChat;

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 android.widget.ScrollView;

/**
 * 有弹性的ScrollView 实现下拉弹回和上拉弹回
 */
public class ReboundScrollView extends ScrollView {

	private static final String TAG = "ElasticScrollView";

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

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

	// 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 ReboundScrollView(Context context) {
		super(context);
	}

	public ReboundScrollView(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());
	}

	/**
	 * 在该方法中获取ScrollView中的唯一子控件的位置信息 这个位置信息在整个控件的生命周期中保持不变
	 */

	/**
	 * 在触摸事件中, 处理上拉和下拉的逻辑
	 */
	@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);
			long time = Math.abs(contentView.getTop() - originalRect.top)
					* ANIM_TIME / 50l;
			anim.setDuration(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();
	}

}

MyListAdapter.java

package com.example.imitateWeChat;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.example.imitateWeChat.DragImageView.MODE;
import com.example.imitateWeChat.DragImageView.OnClickCallback;

public class MyListAdapter extends BaseAdapter {
	private Context mContext;
	private List<ImageListDomain> lists;
	private int resource;
	private LayoutInflater inflater;
	private int state_height;

	public MyListAdapter(Context context, List<ImageListDomain> lists,
			int resource) {
		super();
		this.mContext = context;
		this.lists = lists;
		this.resource = resource;
		inflater = (LayoutInflater) context
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return lists.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return lists.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ImageView imageView = null;
		TextView titleView = null;
		TextView contentView = null;
		if (convertView == null) {
			convertView = inflater.inflate(resource, null);// 生成条目界面对象
			titleView = (TextView) convertView.findViewById(R.id.titleView);
			contentView = (TextView) convertView.findViewById(R.id.contentView);
			imageView = (ImageView) convertView.findViewById(R.id.imageView);
			ViewCache cache = new ViewCache();
			cache.titleView = titleView;
			cache.contentView = contentView;
			cache.imageView = imageView;
			convertView.setTag(cache);
		} else {
			ViewCache cache = (ViewCache) convertView.getTag();
			titleView = cache.titleView;
			contentView = cache.contentView;
			imageView = cache.imageView;
		}
		ImageListDomain list = lists.get(position);
		// 下面代码实现数据绑定
		titleView.setText(list.getTitle());
		contentView.setText(list.getContent());
		imageView.setImageResource(list.getImage());
		// 显示popupwindow
		final PopupWindow popwindow = initPopwindow(BitmapFactory
				.decodeResource(mContext.getResources(), list.getImage()));
		imageView.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				popwindow.showAtLocation(v, Gravity.NO_GRAVITY, 0, 0);
			}
		});
		return convertView;
	}

	private PopupWindow initPopwindow(Bitmap bitmap) {
		LayoutInflater mInflater = (LayoutInflater) mContext
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		final View view = mInflater
				.inflate(R.layout.popwindow_show_image, null);
		final DragImageView drag = (DragImageView) view
				.findViewById(R.id.div_main);
		final PopupWindow popwindow = new PopupWindow(view,
				Util.getScreenWidth(), Util.getScreenHeight());
		popwindow.setFocusable(true);
		popwindow.setBackgroundDrawable(new BitmapDrawable());// 不设置的话返回键无效
		popwindow.setTouchable(true);
		popwindow.setOutsideTouchable(true);
		popwindow.setAnimationStyle(R.style.PopDownMenu);
		view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT));
		view.setOnTouchListener(new OnTouchListener() {
			private boolean onlyClick;

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				/** 处理单点、多点触摸 **/
				switch (event.getAction() & MotionEvent.ACTION_MASK) {
				case MotionEvent.ACTION_DOWN:
					onlyClick = true;
					drag.onTouchDown(event);
					break;
				// 多点触摸
				case MotionEvent.ACTION_POINTER_DOWN:
					onlyClick = false;
					drag.onPointerDown(event);
					break;

				case MotionEvent.ACTION_MOVE:
					onlyClick = false;
					drag.onTouchMove(event);
					break;
				case MotionEvent.ACTION_UP:
					drag.mode = MODE.NONE;
					if (onlyClick) {
						popwindow.dismiss();
					}
					break;
				// 多点松开
				case MotionEvent.ACTION_POINTER_UP:
					drag.mode = MODE.NONE;
					/** 执行缩放还原 **/
					if (drag.isScaleAnim) {
						drag.doScaleAnim();
					}
					break;
				}
				return true;// 返回false无法监听
			}
		});
		drag.setImageBitmap(bitmap);
		drag.setmActivity((Activity) mContext);
		drag.setOnClickCallBack(new OnClickCallback() {

			@Override
			public void callback() {
				popwindow.dismiss();
			}
		});
		ViewTreeObserver viewTreeObserver = drag.getViewTreeObserver();
		viewTreeObserver
				.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

					@Override
					public void onGlobalLayout() {
						if (state_height == 0) {
							// 获取状况栏高度
							Rect frame = new Rect();
							((Activity) mContext).getWindow().getDecorView()
									.getWindowVisibleDisplayFrame(frame);
							state_height = frame.top;
							drag.setScreen_H(Util.getScreenHeight()
									- state_height);
							drag.setScreen_W(Util.getScreenWidth());
						}

					}
				});
		return popwindow;
	}

	private final class ViewCache {
		public TextView titleView;
		public TextView contentView;
		public ImageView imageView;
	}
}

MyListView.java


package com.example.imitateWeChat;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;

public class MyListView extends ListView {

	public MyListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
	}

	public MyListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public MyListView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 根据模式计算每个child的高度和宽度
		int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
				MeasureSpec.AT_MOST);
		super.onMeasure(widthMeasureSpec, expandSpec);
	}
}

代码中注释已经很全了,也就不多说了


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值