본문 바로가기
개발/android

일반뷰를 맵뷰처럼 밀어서 스크롤 시키기

by 매몰 2016. 2. 29.

 

 

 

맵뷰나 스크롤뷰를 손가락으로 살짝 밀면 미끄러지듯이 스크롤이 되다가 서시히 멈춘다

이것을 일반뷰에서도 가능하게 해보자~

 

기본적인 개념은 이렇다

 

손가락이 닿았을때 좌표와 시간을 저장하고

손가락이 떨어졌을때 저장된 좌표와 현재 좌표의 차를 계산해 거리와 방향을 구한다

그리고 시간의 차도 계산해 거리와 나눠 속도를 구한다

이것을 스레드로 속도를 서서히 줄이면서 계속 스크롤 해주면 된다.

 

소스로 보면 더 잘 이해될것이다.

 

 

private View mView;
private long mTime;
private ScrollThread mThread;

@Override
public boolean onTouchEvent(MotionEvent event) {
float touchx = event.getX();
float touchy = event.getY();

switch (event.getAction()) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
//밀었을때에는 밀기 스크롤 스레드를 시작하고 아니면 일반 스크롤을 한다
if (!startScroll(mTouchX, mTouchY, touchx, touchy, mTime, System.currentTimeMillis()))
mView.scrollBy((int) (mTouchX - touchx), (int) (mTouchY - touchy));

break;

case MotionEvent.ACTION_MOVE:
//밀지않고 일반적인 스크롤일경우
mView.scrollBy((int) (mTouchX - touchx), (int) (mTouchY - touchy));
break;

case MotionEvent.ACTION_DOWN:
//시작시간을 저장한다
mTime = System.currentTimeMillis();

//밀기 스크롤 스레드를 중지한다
if(mThread != null) {
mThread.cancel();
mThread = null;
}
}

//시작점을 저장한다
mTouchX = touchx;
mTouchY = touchy;
return true;
}

public boolean startScroll(float startx, float starty, float endx, float endy, long starttime, long endtime) {
if(mThread == null) {
//시간을 계산한다
long time = endtime - starttime;

//일정시간 이상일때만 적용한다
//(그냥 터치일때는 제외하기 위해서)
//(수치는 각자 알아서 변경할것)
if (time > 0 && time < 150) {
//거리를 계산한다
float dx = endx - startx;
float dy = endy - starty;
double distance = Math.sqrt((dx * dx) + (dy * dy));

//일정거리 이상, 이하일때만 적용한다
//(그냥 터치일때는 제외하기 위해서)
//(수치는 각자 알아서 변경할것)
if (distance > 10 && distance < 500) {
//방향을 계산한다
float normalx = (float) (dx / distance);
float normaly = (float) (dy / distance);

//속도를 계산한다
//(기본속도 20은 각자 알아서 변경할것)
float speed = (float) (distance / time) * 20;

//밀기 스크롤 스레드를 시작한다
mThread = new ScrollThread(normalx, normaly, speed);
mThread.start();

return true;
}
}
}

return false;
}

public class ScrollThread extends Thread {

private boolean mRun;
private float mNormalX, mNormalY, mSpeed;

public ScrollThread(float normalx, float normaly, float speed) {
mRun = true;
mNormalX = normalx;
mNormalY = normaly;
mSpeed = speed;
}

public void cancel() {
mRun = false;
}

@Override
public void run() {
while (mRun) {
//속도를 서서히 줄인다
//(수치는 알아서 변경할것)
mSpeed *= 0.94f;
//속도가 1이하면 스레드를 종료한다
if(mSpeed < 1)
break;

//이동량을 스크롤 핸들러로 보낸다
Bundle bundle = new Bundle();
bundle.putInt(MainActivity.KEY_X, (int)(mNormalX * mSpeed));
bundle.putInt(MainActivity.KEY_Y, (int) (mNormalY * mSpeed));

Message msg = mScrollHandler.obtainMessage();
msg.setData(bundle);
mScrollHandler.sendMessage(msg);

//부드러운 진행을 위해 슬립을 건다
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

private Handler mScrollHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
//좌표를 이동한다
//(뷰 스크롤좌표는 반대이므로 마이너스를 붙인다)
mView.scrollBy(-bundle.getInt(KEY_X), -bundle.getInt(KEY_Y));
}
};

사업자 정보 표시
주식회사 머리말 | 고영진 | 서울특별시 송파구 중대로 135 서관 10층 (가락동, 아이티벤처타워) | 사업자 등록번호 : 524-88-00727 | TEL : 010-9990-3674 | Mail : gyjmeba@hanmail.net | 통신판매신고번호 : 2017-서울강남-03941호 | 사이버몰의 이용약관 바로가기