在开发过程中需要做一个相册遇到 一个问题。需要对图片进行布局;当时效果图是
当时我使用的是一个固定布局和一个gridview结合起来做成的。。现在使用自定义groupview将这个效果实现
效果图如下:
接下来到了自定义groupview的时候啦
package com.ww.mypicture;
import java.util.ArrayList;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Scroller;
public class MyPhotoView extends ViewGroup implements OnGestureListener{
private int driverDP=0;
private int imageWidth;
private int currentWidth=0;
private int currentHeight=0;
private ArrayList<String> url=new ArrayList<>();
private int width;
private float mLastMotionY;// 最后点击的点
private GestureDetector detector;
int move = 0;// 移动距离
int MAXMOVE = 850;// 最大允许的移动距离
private Scroller mScroller;
int up_excess_move = 0;// 往上多移的距离
int down_excess_move = 0;// 往下多移的距离
private final static int TOUCH_STATE_REST = 0;
private final static int TOUCH_STATE_SCROLLING = 1;
private int mTouchSlop;
private int mTouchState = TOUCH_STATE_REST;
public MyPhotoView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
detector = new GestureDetector(this);
final ViewConfiguration configuration = ViewConfiguration.get(context);
// 获得可以认为是滚动的距离
mTouchSlop = configuration.getScaledTouchSlop();
/*WindowManager dmManager=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dmDisplayMetrics=new DisplayMetrics();
dmManager.getDefaultDisplay().getMetrics(dmDisplayMetrics);
Swidth=dmDisplayMetrics.widthPixels;*/
TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.MyPhotoView);
driverDP= (int) array.getDimension(R.styleable.MyPhotoView_driverDP, 0);
array.recycle();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
if (changed) {
imageWidth=(getMeasuredWidth()-driverDP*2-getPaddingLeft()-getPaddingRight())/3;
int count =getChildCount();
for (int i = 0; i < url.size(); i++) {
getCurrentSize(i);
if (i==0) {
width=imageWidth*2+driverDP;
}else {
width=imageWidth;
}
View child=getChildAt(i);
LinearLayout.LayoutParams lParams;
lParams=new LinearLayout.
LayoutParams(width, width);
child.setLayoutParams(lParams);
child.layout(currentWidth, currentHeight, currentWidth+width, currentHeight+width);
}
}
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
// 返回当前滚动X方向的偏移
scrollTo(0, mScroller.getCurrY());
postInvalidate();
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final float y = ev.getY();
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
mLastMotionY = y;
mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
: TOUCH_STATE_SCROLLING;
break;
case MotionEvent.ACTION_MOVE:
final int yDiff = (int) Math.abs(y - mLastMotionY);
boolean yMoved = yDiff > mTouchSlop;
// 判断是否是移动
if (yMoved) {
mTouchState = TOUCH_STATE_SCROLLING;
}
break;
case MotionEvent.ACTION_UP:
mTouchState = TOUCH_STATE_REST;
break;
}
return mTouchState != TOUCH_STATE_REST;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
MAXMOVE=(url.size()/3+url.size()%3==0?0:1+2)*(imageWidth+driverDP)-driverDP;
final float y = ev.getY();
switch (ev.getAction())
{
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.forceFinished(true);
move = mScroller.getFinalY();
}
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
if (ev.getPointerCount() == 1) {
// 随手指 拖动的代码
int deltaY = 0;
deltaY = (int) (mLastMotionY - y);
mLastMotionY = y;
if (deltaY < 0) {
// 下移
// 判断上移 是否滑过头
if (up_excess_move == 0) {
if (move > 0) {
int move_this = Math.max(-move, deltaY);
move = move + move_this;
scrollBy(0, move_this);
} else if (move == 0) {// 如果已经是最顶端 继续往下拉
down_excess_move = down_excess_move - deltaY / 2;// 记录下多往下拉的值
scrollBy(0, deltaY / 2);
}
} else if (up_excess_move > 0)// 之前有上移过头
{
if (up_excess_move >= (-deltaY)) {
up_excess_move = up_excess_move + deltaY;
scrollBy(0, deltaY);
} else {
up_excess_move = 0;
scrollBy(0, -up_excess_move);
}
}
} else if (deltaY > 0) {
// 上移
if (down_excess_move == 0) {
if (MAXMOVE - move > 0) {
int move_this = Math.min(MAXMOVE - move, deltaY);
move = move + move_this;
scrollBy(0, move_this);
} else if (MAXMOVE - move == 0) {
if (up_excess_move <= 100) {
up_excess_move = up_excess_move + deltaY / 2;
scrollBy(0, deltaY / 2);
}
}
} else if (down_excess_move > 0) {
if (down_excess_move >= deltaY) {
down_excess_move = down_excess_move - deltaY;
scrollBy(0, deltaY);
} else {
down_excess_move = 0;
scrollBy(0, down_excess_move);
}
}
}
}
break;
case MotionEvent.ACTION_UP:
// 多滚是负数 记录到move里
if (up_excess_move > 0) {
// 多滚了 要弹回去
scrollBy(0, -up_excess_move);
invalidate();
up_excess_move = 0;
}
if (down_excess_move > 0) {
// 多滚了 要弹回去
scrollBy(0, down_excess_move);
invalidate();
down_excess_move = 0;
}
mTouchState = TOUCH_STATE_REST;
break;
}
return this.detector.onTouchEvent(ev);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
for(int i=0;i<url.size();i++){
// MyImageView imageView=new MyImageView(getContext());
ImageView imageView=new ImageView(getContext());
// imageView.setImage(R.drawable.ic_launcher);
imageView.setImageDrawable(getContext().getResources().getDrawable(R.drawable.img_sex_boy_pressed));
imageView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
addView(imageView,i);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void getCurrentSize(int i){
if (i<3) {
if (i==0) {
currentWidth=getPaddingLeft();
}else {
currentWidth=getPaddingLeft()+(imageWidth+driverDP)*2;
}
if (i==2) {
currentHeight=imageWidth+driverDP+getPaddingTop();
}else {
currentHeight=getPaddingTop();
}
}else {
currentWidth=i%3*(imageWidth+driverDP)+getPaddingLeft();
currentHeight=(i/3+1)*(imageWidth+driverDP)+getPaddingTop();
}
}
public void setUrl(ArrayList<String> urlString){
url.clear();
if (urlString!=null) {
url.addAll(urlString);
}
}
public void addUrl(ArrayList<String> urlString){
if (urlString!=null) {
url.addAll(urlString);
}
}
public void setDriverDP(int dp){
this.driverDP=dp;
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
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;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
int Fling_move = 0;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (up_excess_move == 0 && down_excess_move == 0) {
int slow = -(int) velocityY * 3 / 4;
mScroller.fling(0, move, 0, slow, 0, 0, 0, MAXMOVE);
move = mScroller.getFinalY();
computeScroll();
}
return false;
}
}
其中自定义控件和布局是在onMeasur()和onLayout()方法中。。实现滑动效果是对事件进行重写(此处是借鉴度娘上的代码)关于此处本人还有待学习。。
由于只是测试demo所以还有很多地方需要完善,,,比方说点击效果分页等等。。
其他的布局使用和逻辑控制代码都比较简单。。所以就不多说了。。。