android 가로 스크롤 슬라이딩 메뉴(Sliding Menu)

HorizontalScrollView를 상속받아 구현






<스크롤뷰 초기 이동>

- 스크롤뷰 초기 설정이 동작하지 않는다. ex) scrollView.scrollTo(x,y)

- 그때는 이렇게 하면 된다.

scrollView.post(new Runnable(){
            public void run() {
                scrollView.scrollTo(x, y);
            }
 });


- 만약 0.1초 정도의 딜레이를 주고 스크롤 뷰를 움직이고 싶다면..


scrollView.postDelayed(new Runnable(){
            public void run() {
                scrollView.scrollTo(x, y);
            }
 }, 100);

< scrollTo, scrollBy, smoothScrollTo >

scrollBy(x,y) 해당뷰의 현재좌표에서 가로 x만큼, 세로 y만큼 이동

scrollTo(x,y) 해당뷰의 절대좌표 x,y 로 이동함

smoothScrollTo(x,y) 해당뷰의 절대좌표 x,y 로 부드럽게 이동



아래 소스는 화면 캡춰하는 소스도 포함되었으니 알아서 보세요..

< MiniMyTestActivity.java 소스 >

package dingdong.util.minimytest;


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;

public class MiniMyTestActivity extends Activity{
	View capView;  // 캡춰
	private MenuSlideView mSlideView;
	private Context mContext;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        setContentView(R.layout.main);
        Button bt_capture = (Button)findViewById(R.id.bt_capture);
        Button bt_scrollTo = (Button)findViewById(R.id.bt_scrollTo);
        LinearLayout ly_main = (LinearLayout)findViewById(R.id.ly_main);
        bt_capture.setOnClickListener(mClickListener);
        bt_scrollTo.setOnClickListener(mClickListener);
        
        capView = ly_main;  // 리니어 레이아웃 캡춰
//        capView = getWindow().getDecorView();  // 전체 화면 캡춰

        mSlideView = (MenuSlideView)findViewById(R.id.menu_slide);

        // 이게 왜 안되지?  --> 아래처럼 하면 동작함
//        mSlideView.post(new Runnable(){
//            public void run() {
//        		//get screen size, move default scroll position
//        		Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
//        		int mScreenWidth = display.getWidth();
//            	mSlideView.scrollTo(mScreenWidth/3, 0);
//            }
//        });
		
      mSlideView.moveDefault(0,3);

        
    }

    protected void onResume() {
		super.onResume();
		mContext = this;

    };
    
	View.OnClickListener	mClickListener = new View.OnClickListener() {
		@Override
		public void onClick(View v) {
			
			switch (v.getId()) {
				case R.id.bt_capture:		 

						try {
							screenshot(capView);
						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					break;
				case R.id.bt_scrollTo:		 

					try {
						//get screen size, move default scroll position
						Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
						int mScreenWidth = display.getWidth();
						mSlideView.smoothScrollTo(mScreenWidth/3, 0);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				break;
			
				default:
					break;
			}
		}
	};    
    
	public void screenshot (View view) throws Exception{
		view.setDrawingCacheEnabled(true);
		Bitmap scrreenshot = view.getDrawingCache();
		String filename = "screenshot.png";
		try{
			File f = new File(Environment.getExternalStorageDirectory(),filename);
			f.createNewFile();
			OutputStream outStream = new FileOutputStream(f);
			scrreenshot.compress(Bitmap.CompressFormat.PNG, 100, outStream);
			outStream.close();
			
		}catch( IOException e){
			e.printStackTrace();
		}
		view.setDrawingCacheEnabled(false);
	}    
}

< MenuSlideView.java 소스 >

package dingdong.util.minimytest;


import android.content.Context;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.Toast;

/**
 * @author damianjj
 *
 */
public class MenuSlideView extends HorizontalScrollView{
	private Context mContext;
	private int mScreenWidth;
	private static final String TAG = "MiniApp";
    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private int mCurPosX = 0;
    ImageView iv_left;
    private int mMoveDefault = -1;
	
	//Gesture
	private GestureDetector mGesture;
	private GestureDetector.OnGestureListener mGesturesListener = new OnGestureListener(){
		
		@Override
		public boolean onDown(MotionEvent e){
			Log.d(TAG, "start onDown");
			return false;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 	float velocityY) {
			Log.d(TAG, "start onFling");

			// TODO			
			int nScrollX = getScrollX();
			int nScrollY = getScrollY();
			// 지정된 위치로 이동, 부드럽게 이동(smoothScrollTo)
			moveThisPos(nScrollX, nScrollY);
			
//	        try {
//	            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
//	                return false;
//	            
//	            // right to left swipe  <-----------------
//	            if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
//	                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//	            	Toast.makeText(mContext, "<------------ ("+velocityX+","+velocityY+")", Toast.LENGTH_SHORT).show();	                
//	            }
//	            // left to right swipe  ------------>
//	            else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
//	                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//	            	Toast.makeText(mContext, "------------> ("+velocityX+","+velocityY+")", Toast.LENGTH_SHORT).show();
//	            }
//	            // down to up swipe
//	            else if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE
//	                    && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
//	                Toast.makeText(mContext, "Swipe up", Toast.LENGTH_SHORT).show();
//	            }
//	            // up to down swipe
//	            else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE
//	                    && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
//	                Toast.makeText(mContext, "Swipe down", Toast.LENGTH_SHORT).show();
//	            }
//	        } catch (Exception e) {
//	            
//	        }			
			
			return false;
		}

		@Override
		public void onLongPress(MotionEvent e) {
			Log.d(TAG, "start onLongPress");
		}

		@Override
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//			Log.d(TAG, "start onScroll");
			smoothScrollBy((int)distanceX,0);  // 스크롤할때 따라오기
			int nScrollX = getScrollX(); // 스크롤 현위치
			int nScrollY = getScrollY();
//			Toast.makeText(mContext, "onScroll, nScrollX="+nScrollX+", nScrollY="+nScrollY+",("+distanceX+","+distanceY+")", Toast.LENGTH_SHORT).show();
//			Log.d(TAG, "onScroll, nScrollX="+nScrollX+", nScrollY="+nScrollY+",("+distanceX+","+distanceY+")");	
			return false;
		}

		@Override
		public void onShowPress(MotionEvent e) {
			Log.d(TAG, "start onShowPress");
			
		}

		@Override
		public boolean onSingleTapUp(MotionEvent e) {
			Log.d(TAG, "start onSingleTapUp");
			return false;
		}
		
	};
	
	
	public MenuSlideView(Context context) {
		super(context);
		mContext = context;
		createSubView();
	}


	public MenuSlideView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mContext = context;
		createSubView();
	}


	public MenuSlideView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
		createSubView();
	}


	private void createSubView() {
		mGesture = new GestureDetector(mContext, mGesturesListener);
		
		//scroll view setting
		setHorizontalScrollBarEnabled(false);
		
		//get screen size
		Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
		mScreenWidth = display.getWidth();
		Toast.makeText(mContext, "mSW="+mScreenWidth, Toast.LENGTH_SHORT).show();
		
		//set sub layout
		LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View v = inflater.inflate(R.layout.menu_layout, null);
		iv_left = (ImageView)v.findViewById(R.id.iv_left);
//		iv_left.setVisibility(View.GONE);  // 자리 안차지
		iv_left.setVisibility(View.INVISIBLE);  // 자리 차지
    	
		ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, 100); // 높이 100
		addView(v,params);
		
	}
	
	public void moveDefault(int x, int count){
		if(count != 0){
			mMoveDefault = mScreenWidth/count;
		}else{
			mMoveDefault = x;
		}
		
		// 스크롤바 초기 이동
        post(new Runnable(){
            public void run() {
        		//get screen size, move default scroll position
            	scrollTo(mMoveDefault, 0);
            }
        });		

        mCurPosX = mMoveDefault;


	}


	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		int nScrollX = getScrollX();
		int nScrollY = getScrollY();
		float nMoveX = ev.getX();
		float nMoveY = ev.getY();		
		
		
		mGesture.onTouchEvent(ev);
		int action = ev.getAction();
		switch(action){
		
		case MotionEvent.ACTION_MOVE:
			Log.d(TAG, "ACTION_MOVE: getScrollX()="+getScrollX());
			
			break;		
		case MotionEvent.ACTION_UP:	// TODO

			// 지정된 위치로 이동, 부드럽게 이동(smoothScrollTo)
			moveThisPos(nScrollX, nScrollY);
//			
//			Toast.makeText(mContext, "ACTION_UP: Scroll("+nScrollX+","+nScrollY+")"+"  POS("+nMoveX+","+nMoveY+")", Toast.LENGTH_SHORT).show();
//			Log.d(TAG, "ACTION_UP: Scroll("+nScrollX+","+nScrollY+")"+"  POS("+nMoveX+","+nMoveY+")");
			
			break;
		}
		
		return true;
	}
	
	// 지정된 위치로 이동
	public void moveThisPos(int nScrollX, int nScrollY){
		if(nScrollX < mScreenWidth/6){
			smoothScrollTo(0,0);
		}else if(nScrollX >= mScreenWidth/6 && nScrollX < mScreenWidth/3){
			smoothScrollTo(mScreenWidth/3,0);
		}else if(nScrollX >= mScreenWidth/3 && nScrollX < mScreenWidth/2){
			smoothScrollTo(mScreenWidth/3,0);		
		}else if(nScrollX >= (mScreenWidth/2) && nScrollX < (mScreenWidth/3*2)){
			smoothScrollTo(mScreenWidth/3*2,0);			
		}else if(nScrollX >= (mScreenWidth/3+mScreenWidth/3) && nScrollX < (mScreenWidth/6*5)){
			smoothScrollTo(mScreenWidth/3*2,0);							
		}else if(nScrollX >= (mScreenWidth/6*5) && nScrollX < (mScreenWidth)){
			smoothScrollTo(mScreenWidth,0);							
		}					
	}
	
}

< Menu_layout.xml 소스 >


    

        
                
        

          
        
        
                
    

< main.xml 소스 >




    

    

<참고 자료>

@@ Sliding Menu @@

https://github.com/gitgrimbo/android-sliding-menu-demo


SlidingMenuDemo.zip

---> 좋은 소스임.. 참고하세요..


@ Sliding Toggle 버튼 만들기(SlidingDrawer 상속) @

http://www.androidpub.com/878847


@@ 슬라이드바 @@

android animation slidedown slideup

Android Sliding Drawer 

http://ememomo.tistory.com/tag/Slide

http://ememomo.tistory.com/51


@@ 좌우 슬라이딩 @@

http://blog.naver.com/PostView.nhn?blogId=rosaria1113&logNo=115530732&categoryNo=76&viewDate=&currentPage=1&listtype=0

--> 주로 이소스를 수정하여서 만들었음.


@Android: Making a TextView Scrollable

http://www.gubatron.com/blog/2010/04/19/android-making-a-textview-scrollable/


@@@ API Demos - ImageSwitcher @@@

  최근까지 여기저기 삽질을 해본결과 

안드로이드에 기본제공되는 API Demos의 Views - ImageSwitcher 소스를 참고해서 

가로 이미지 스크롤 메뉴나, 가로 텍스트 스크롤메뉴를 만드는것이 가장 좋아보임.  

즉 Gallery 를 이용하는것이 젤 좋아보임.. 이 방식이 스크롤 동작이 가장 부드럽고, 터치시에 가운데로 움직이는 기능도 있어서 좋다.

10점만점에 10점..

이것을 이용해서 만든 앱(SK Btv 방송 편성표)..

Btv 편성표 다운로드   (안드로이드 마켓 이동)


여기는 참고자료..

http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/ImageSwitcher1.html



< 가로 스크롤뷰를 상속하여 만든 메뉴 소스 다운로드 >


MiniMyTest.zip


(추신 : 소스 다운로드시에 감사의 댓글을~~~)


(SyntaxHighlighter를 처음 적용해봐서.. 레이아웃이 좀 깨지네요.. ㅠ.ㅠ 그래도 소스 보기는 좋은듯..)



+ Recent posts