Search

'세로스크롤 갤러리'에 해당되는 글 1건

  1. 2011.07.03 세로스크롤이 되는 갤러리

세로스크롤이 되는 갤러리

Android 2011.07.03 13:23 Posted by 기분째즈
가로스크롤로 그림은 넘기면서 안에 있는 내용물은 세로스크롤이 되는 갤러리입니다. 그림을 넘기는 부분까지 세로스크롤을 원한다면 Gallery를 상속받을 게 아니라 ListView를 상속받아서 사용해야합니다. Gallery는 가로스크롤 밖에 되지 않습니다.

동영상을 보면 이해가 가실 겁니다.
 


간단히 해결될 문제처럼 보이지만 그리 간단한 문제가 아닙니다. 그냥 getView에 이미지를 보여주는 게 아니라 스크롤뷰로 한번싸면 될 거 같지만, 그러면 스크롤뷰가 이벤트를 다 가져가 버려서 가로스크롤이 되지 않습니다. dispatchTouchEvent를 쓰면 둘 다 작동은 되지만 손가락이 일직선으로 좌우로 움직이는 게 아니기 때문에 의도한대로 스크롤 되는 게 아니라 정말 손가락 움직이는대로 움직이게 됩니다. 동영상처럼 세로스크롤만 하려고 했는데 오른쪽 왼쪽에 있는 그림들이 들어갔다 나왔다 거리죠.

onTouchEvent를 상속받아서 손가락이 가로로 움직이면 갤러리에서 처리하고 세로로 움직이면 스크롤뷰에서 처리하면 될 거 같지만, 인간의 손가락은 그렇게 정확하게 움직여주지 않습니다. 가로로 움직이려고 했는데,  첫 터치는 세로로 움직일 수도 있거든요...

한가지 방법은 갤러리에서 터치이벤트를 모두 낚아채서 첫터치 이후 일정거리(예제에서는 1/15인치)를 가로로 움직이면 가로 스크롤, 세로로 움직이면 세로스크롤로 처리하는 방법이 있습니다. 주의사항은 세로스크롤로 보낼 때는 첫 이벤트인 것처럼 위장하기 위해서 마우스이벤트를 DOWN이벤트로 수정해줘야합니다.

# 한장씩 넘어가는 갤러리 
# 어댑터안에서 메모리 관리하기
에서 중요한 소스는 설명했기 때문에 그냥 전체소스만 붙이겠습니다. 말로 하는 것보다 소스를 보시는 게 더 이해가 빠를 수 있으니까요.

OneFlingScrollGallery.java

package com.givenjazz.android;


import android.content.Context;

import android.hardware.SensorManager;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.ViewConfiguration;

import android.widget.Gallery;


public class OneFlingScrollGallery extends Gallery {

    private static final int NOTHING = 0;

    private static final int HORIZONTAL = 1;

    private static final int VERTICAL = 2;


    private float mSensitivity;

    

    private float mDownX;

    private float mDownY;

    private boolean mNeedToPosition;

    private boolean mNeedToJudge;

    private int mDirection;


    private float mDistanceX;

    private float mDeceleration;


    public OneFlingScrollGallery(Context context) {

        this(context, null);

    }


    public OneFlingScrollGallery(Context context, AttributeSet attrs) {

        super(context, attrs);

        float ppi = context.getResources().getDisplayMetrics().density * 160.0f;

        mSensitivity = ppi/15; // 민감도 1/15인치

        mDeceleration = SensorManager.GRAVITY_EARTH // g (m/s^2)

                * 39.37f // inch/meter

                * ppi // pixels per inch

                * ViewConfiguration.getScrollFriction();

    }


    @Override

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {


        float toMoveDistance = getWidth() - Math.abs(mDistanceX);

        float maxVelocity = (float)Math.sqrt(toMoveDistance * mDeceleration * 2);

        float revisedVelocityX = 0;


        if (velocityX > 0) {

            revisedVelocityX = Math.min(velocityX, maxVelocity);

        } else {

            revisedVelocityX = Math.max(velocityX, -maxVelocity);

        }


        return super.onFling(e1, e2, revisedVelocityX, velocityY);

    }


    @Override

    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {


        if (mNeedToPosition) {

            mDistanceX = 0;

            mNeedToPosition = false;

            distanceX = 0;

        }

        mDistanceX += distanceX;

        return super.onScroll(e1, e2, distanceX, distanceY);

    }


    @Override

    public boolean onTouchEvent(MotionEvent e) {

        switch (mDirection) {

            case HORIZONTAL:

                return super.onTouchEvent(e);

            case VERTICAL:

                if (mNeedToJudge == true) {

                    mNeedToJudge = false;

                    //스크롤뷰에서 처음 받을 이벤트이니 다운이벤트로 위장

                    e.setAction(MotionEvent.ACTION_DOWN);

                }


                //스크롤뷰로 이벤트 전달

                getSelectedView().onTouchEvent(e);

                return true;

            case NOTHING:

                float deltaX = Math.abs(e.getX() - mDownX);

                float deltaY = Math.abs(e.getY() - mDownY);

                if (deltaX > deltaY + mSensitivity)

                    mDirection = HORIZONTAL;

                else if (deltaX + mSensitivity < deltaY)

                    mDirection = VERTICAL;


        }

        return true;

    }


    @Override

    public boolean onInterceptTouchEvent(MotionEvent e) {

        mDirection = NOTHING;

        mNeedToPosition = true;

        mNeedToJudge = true;

        mDownX = e.getX();

        mDownY = e.getY();

        return true;

    }


}



ImageAdapter.java (소스의 간결함을 위해 convertView 사용은 생략) 

package com.givenjazz.android;


import java.lang.ref.WeakReference;

import java.util.ArrayList;

import java.util.List;


import android.content.Context;

import android.util.Log;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.Gallery;

import android.widget.ImageView;

import android.widget.ScrollView;


public class ImageScrollAdapter extends BaseAdapter {

    private List<Integer> mResources;

    private Context mContext;

    private List<WeakReference<View>> mRecycleList = new ArrayList<WeakReference<View>>();


    public ImageScrollAdapter(Context c, List<Integer> resources) {

mContext = c;

mResources = resources;

    }


    @Override

    public int getCount() {

return mResources.size();

    }


    @Override

    public Object getItem(int position) {

return mResources.get(position);

    }


    @Override

    public long getItemId(int position) {

return position;

    }


    public void recycle() {

RecycleUtils.recursiveRecycle(mRecycleList);

    }


    public void recycleHalf() {

int halfSize = mRecycleList.size() / 2;

List<WeakReference<View>> recycleHalfList = mRecycleList.subList(0,

halfSize);

RecycleUtils.recursiveRecycle(recycleHalfList);

for (int i = 0; i < halfSize; i++)

    mRecycleList.remove(0);

    }


    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

ScrollView scrollView = new ScrollView(mContext);

ImageView i = new ImageView(mContext);


try {

    i.setImageResource(mResources.get(position));

} catch (OutOfMemoryError e) {

    if (mRecycleList.size() <= parent.getChildCount()) {

Log.e(this + "", "size:" + mRecycleList.size());

throw e;

    }

    Log.w(this + "", e.toString());

    recycleHalf();

    System.gc();

    return getView(position, scrollView, parent);

}

i.setAdjustViewBounds(true);

i.setLayoutParams(new Gallery.LayoutParams(i.getDrawable()

.getIntrinsicWidth(), i.getDrawable().getIntrinsicHeight()));


scrollView.addView(i);


mRecycleList.add(new WeakReference<View>(scrollView));

return scrollView;

    }

}



라이센스는 언제나 그렇듯이 아파치2.0으로 공개합니다.

신고


 

티스토리 툴바