Search

'Android'에 해당되는 글 11건

  1. 2011.09.05 Support4Demos API 8 수정버전 (4)
  2. 2011.07.03 세로스크롤이 되는 갤러리

Support4Demos API 8 수정버전

Android 2011.09.05 19:41 Posted by 기분째즈



Compatibility Package라 불리는 안드로이드 확장 라이브러리의 데모입니다.

원본은 최소사양이 API11인데 API8로 수정했습니다.

수정했다기 보다 허니콤용 API를 사용하는 소스는 그냥 삭제했고요.

FragmentTab과 Loader를 삭제했는데, 어차피 핵심은 Fragment니 그것만 보시면 될겁니다.

예전에 한장씩 넘어가는 갤러리를 구현한 적이 있는데,  이번에 추가된 FragmentPager로 구현하는 게 더 깔끔하고 편하겠네요.

갤러리는 Deprecated 시키고 ViewPager로 간단히 구현해서 이번 주 중으로 올리도록 하겠습니다.
신고

세로스크롤이 되는 갤러리

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으로 공개합니다.

신고


 

티스토리 툴바