메뉴 건너뛰기

조회 수 12535 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄 첨부
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄 첨부

페이스북 앱을 보면 좌측 메뉴 버튼을 눌렀을 때 좌측에서 슬라이드로 메뉴가 나오게 됩니다. 


원리는 메인화면을 구성하는 xml에 전체를 FrameLayout으로 감싸고 내부에 메뉴 레이아웃을 깔고 


그 위에 메인 화면의 레이아웃을 포개어 놓습니다. 그러고 메인화면의 메뉴 버튼을 눌렀을 때 메인화면 레이아웃을


애니메이션 처리하여 우측으로 밀어버려 아래에있던 메뉴 레이아웃이 노출되는 식입니다. 







<activity_main.xml>




구성요소는 다음과 같습니다.


1. MainActivity.java

2. OpenAnimation.java

3. CloseAnimation.java

4. activity_main.xml

5. leftslidemenu.xml



먼저 MainActivity 입니다. 



public class MainActivity extends Activity implements OnClickListener {

	// slide menu 
	private DisplayMetrics metrics;
	private LinearLayout ll_mainLayout;
	private LinearLayout ll_menuLayout;
	private FrameLayout.LayoutParams leftMenuLayoutPrams;
	private int leftMenuWidth;
	private static boolean isLeftExpanded;

	private Button bt_left, btn1, btn2, btn3, btn4;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		initSildeMenu();

	}

	private void initSildeMenu() {

		// init left menu width
		metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		leftMenuWidth = (int) ((metrics.widthPixels) * 0.75);

		// init main view
		ll_mainLayout = (LinearLayout) findViewById(R.id.ll_mainlayout);

		// init left menu
                ll_menuLayout = (LinearLayout) findViewById(R.id.ll_menuLayout);
		leftMenuLayoutPrams = (FrameLayout.LayoutParams) ll_menuLayout
				.getLayoutParams();
		leftMenuLayoutPrams.width = leftMenuWidth;
		ll_menuLayout.setLayoutParams(leftMenuLayoutPrams);

		// init ui
		bt_left = (Button) findViewById(R.id.bt_left);
		bt_left.setOnClickListener(this);

		btn1 = (Button) findViewById(R.id.btn1);
		btn2 = (Button) findViewById(R.id.btn2);
		btn3 = (Button) findViewById(R.id.btn3);
		btn4 = (Button) findViewById(R.id.btn4);
		btn1.setOnClickListener(this);
		btn2.setOnClickListener(this);
		btn3.setOnClickListener(this);
		btn4.setOnClickListener(this);
	}

	/**
	 * left menu toggle
	 */
	private void menuLeftSlideAnimationToggle() {

		if (!isLeftExpanded) {

			isLeftExpanded = true;

			// Expand
			new OpenAnimation(ll_mainLayout, leftMenuWidth,
					Animation.RELATIVE_TO_SELF, 0.0f,
					Animation.RELATIVE_TO_SELF, 0.75f, 0, 0.0f, 0, 0.0f);

			// enable all of menu view
			FrameLayout viewGroup = (FrameLayout) findViewById(R.id.ll_menuLayout)
					.getParent();
			enableDisableViewGroup(viewGroup, true);

			// enable empty view
			((LinearLayout) findViewById(R.id.ll_empty))
					.setVisibility(View.VISIBLE);

			findViewById(R.id.ll_empty).setEnabled(true);
			findViewById(R.id.ll_empty).setOnTouchListener(
					new OnTouchListener() {

						@Override
						public boolean onTouch(View arg0, MotionEvent arg1) {
							menuLeftSlideAnimationToggle();
							return true;
						}
					});

		} else {
			isLeftExpanded = false;

			// Collapse
			new CloseAnimation(ll_mainLayout, leftMenuWidth,
					TranslateAnimation.RELATIVE_TO_SELF, 0.75f,
					TranslateAnimation.RELATIVE_TO_SELF, 0.0f, 0, 0.0f, 0, 0.0f);

			
			// enable all of menu view
			FrameLayout viewGroup = (FrameLayout) findViewById(R.id.ll_menuLayout)
					.getParent();
			enableDisableViewGroup(viewGroup, false);

			// disable empty view
			((LinearLayout) findViewById(R.id.ll_empty))
					.setVisibility(View.GONE);
			findViewById(R.id.ll_empty).setEnabled(false);

		}
	}


    public static void enableDisableViewGroup(ViewGroup viewGroup,
			boolean enabled) {
		int childCount = viewGroup.getChildCount();
		for (int i = 0; i < childCount; i++) {


			View view = viewGroup.getChildAt(i);
			view.setEnabled(enabled);

			if (view instanceof ViewGroup) {
				enableDisableViewGroup((ViewGroup) view, enabled);
			}
		}
    }


	@Override
	public void onClick(View v) {

		switch (v.getId()) {
		case R.id.bt_left:
			menuLeftSlideAnimationToggle();
			break;
		case R.id.btn1:
			Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_SHORT)
					.show();
			break;
		case R.id.btn2:
			Toast.makeText(getApplicationContext(), "2", Toast.LENGTH_SHORT)
					.show();
			break;
		case R.id.btn3:
			Toast.makeText(getApplicationContext(), "3", Toast.LENGTH_SHORT)
					.show();
			break;
		case R.id.btn4:
			Toast.makeText(getApplicationContext(), "4", Toast.LENGTH_SHORT)
					.show();
			break;

		}

	}
}


최초에 initSildeMenu()매소드에서 사용 할 메인 레이아웃과 메뉴 레이아웃을 초기화 합니다.


메뉴 레이아웃은 열렸을 때 화면 전체너비로 열리는 것이 아니라 우측에 메인 레이아웃이 살짝 걸치므로 


메뉴 레아이웃 너비가 될 leftMenuWidth 변수에 화면전체 너비에 0.75 정도 비율을 넣어 줍니다. 






이 후에 메인 레이아웃을 findViewById 하고 메뉴 레이아웃도 findViewById 한 후 


아까 만든 0.75의 너비를 width로 넣어줍니다. 나머지 버튼들도 리스너를 달아줍니다. 




이제 핵심이 되는 menuLeftSlideAnimationToggle() 매소드 입니다


토글이라는 말과 같이 메뉴가 열고 닫힐 때 모두 이 매소드를 사용하며


isLeftExpanded라는 boolean 값으로 열고 닫힐 때를 판단하게 됩니다.


우선 열릴 때 입니다.


메뉴버튼을 눌러 메뉴가 열리게 되면 우선 isLeftExpanded = true; 를 줘서 메뉴가 열렸다를 저장하고


OpenAnimation 이란 클래스를 통하여 메뉴가 열리게 됩니다.


처음 구조 설명 할 때 설명을 안했지만 메인 레이아웃 위에 empty 레이아웃을 하나 더 포개었는데


이 뷰를 VISIBLE 시키게 됩니다. 이 ll_empty 뷰는 투명한 뷰이며 


메뉴가 열려있을 때 우측에 살짝 보이는 메인 레이아웃을 덮고 있습니다. 


이 뷰를 터치하면 menuLeftSlideAnimationToggle(); 매소드를 호출하여 메뉴가 닫히게 됩니다. 


이는 꼭 메뉴버튼을 눌러야 메뉴가 닫히는것이 아닌 그냥 메인 뷰만 터치하면 닫히도록하는 편리함을 위함입니다.




public class OpenAnimation extends TranslateAnimation implements
		Animation.AnimationListener {

	private LinearLayout mainLayout
	int panelWidth;

	public OpenAnimation(LinearLayout layout, int width, int fromXType,
			float fromXValue, int toXType, float toXValue, int fromYType,
			float fromYValue, int toYType, float toYValue) {

		super(fromXType, fromXValue, toXType, toXValue, fromYType, fromYValue,
				toYType, toYValue);

		// init
		mainLayout = layout;
		panelWidth = width;
		setDuration(250);
		setFillAfter(false);
		setInterpolator(new AccelerateDecelerateInterpolator());
		setAnimationListener(this);
		mainLayout.startAnimation(this);
	}

	public void onAnimationEnd(Animation arg0) {

		LayoutParams params = (LayoutParams) mainLayout.getLayoutParams();
		params.leftMargin = panelWidth;
		params.gravity = Gravity.LEFT;
		mainLayout.clearAnimation();
		mainLayout.setLayoutParams(params);
		mainLayout.requestLayout();

	}

	public void onAnimationRepeat(Animation arg0) {

	}

	public void onAnimationStart(Animation arg0) {

	}

}


OpenAnimation 클래스입니다. 받아온 속성들로 초기화를 하며 setDuration(250);이 부분이 열릴 때의 속도입니다.



메뉴가 닫힐 때는 isLeftExpanded로 닫힐 때를 가려내고 isLeftExpanded = flase;를 줘 닫힘을 저장합니다.


OpenAnimarion 클래스와 같이 CloseAnimation을 호출하게되고 활성화 되어있던 empty뷰를 꺼서 


메인 레이아웃이 다시 노출되게 합니다.

public class CloseAnimation extends TranslateAnimation implements
		TranslateAnimation.AnimationListener {

	private LinearLayout mainLayout;
	int panelWidth;

	public CloseAnimation(LinearLayout layout, int width, int fromXType,
			float fromXValue, int toXType, float toXValue, int fromYType,
			float fromYValue, int toYType, float toYValue) {

		super(fromXType, fromXValue, toXType, toXValue, fromYType, fromYValue,
				toYType, toYValue);

		// Initialize
		mainLayout = layout;
		panelWidth = width;
		setDuration(250);
		setFillAfter(false);
		setInterpolator(new AccelerateDecelerateInterpolator());
		setAnimationListener(this);

		// Clear left and right margins
		LayoutParams params = (LayoutParams) mainLayout.getLayoutParams();
		params.rightMargin = 0;
		params.leftMargin = 0;
		mainLayout.setLayoutParams(params);
		mainLayout.requestLayout();
		mainLayout.startAnimation(this);

	}

	public void onAnimationEnd(Animation animation) {

	}

	public void onAnimationRepeat(Animation animation) {

	}

	public void onAnimationStart(Animation animation) {

	}

}


CloseAnimation입니다. 



아래엔 사용한 xml 파일입니다.


<-- activity_main.xml -->


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="fill_parent"

    android:layout_height="match_parent"

    android:orientation="vertical" >


    <FrameLayout

        android:layout_width="fill_parent"

        android:layout_height="match_parent"

        android:background="#ffffff"

        android:orientation="vertical" >


        <LinearLayout

            android:id="@+id/ll_menuLayout"

            android:layout_width="match_parent"

            android:layout_height="match_parent"

            android:background="#ff393c46"

            android:gravity="left"

            android:orientation="vertical"

            android:textColor="#ff000000" >


            <!-- include -->


            <include

                android:id="@+id/ic_leftslidemenu"

                android:layout_width="match_parent"

                android:layout_height="match_parent"

                layout="@layout/leftslidemenu" />

        </LinearLayout>


        <!-- slide layout -->


        <LinearLayout

            android:id="@+id/ll_mainlayout"

            android:layout_width="match_parent"

            android:layout_height="match_parent"

            android:background="#ffffffff"

            android:gravity="left"

            android:orientation="vertical" >


            <FrameLayout

                android:layout_width="match_parent"

                android:layout_height="match_parent" >


                <Button

                    android:id="@+id/bt_left"

                    android:layout_width="wrap_content"

                    android:layout_height="wrap_content"

                    android:layout_margin="10dp"

                    android:text="Left Slide" />


                <LinearLayout

                    android:id="@+id/ll_fragment"

                    android:layout_width="match_parent"

                    android:layout_height="wrap_content" >

                </LinearLayout>


                <LinearLayout

                    android:id="@+id/ll_empty"

                    android:layout_width="fill_parent"

                    android:layout_height="fill_parent"

                    android:background="@android:color/transparent" />

            </FrameLayout>

        </LinearLayout>

    </FrameLayout>


</LinearLayout>





<-- leftslidemenu.xml -->


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="fill_parent"

    android:layout_height="match_parent"

    android:background="#994444cc"

    android:orientation="vertical"

    android:padding="10dp" >


    <Button

        android:id="@+id/btn1"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="Button 1 " />


    <Button

        android:id="@+id/btn2"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="Button 2 " />


    <Button

        android:id="@+id/btn3"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="Button 3 " />


    <Button

        android:id="@+id/btn4"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="Button 4 " />


</LinearLayout>



위 처럼 메인 레이아웃에 메뉴 레이아웃이 include 되어있습니다. 




-- 2013 10 04 내용추가 


현재 버전에는 메인 화면에서는 메인 화면이 덮고있는 중에도 터치를 하면 뒤 LeftMenu의 버튼이 눌리게 됩니다. 


초보개발자 님 말씀대로 visible방법도 가능하고 


저는 뷰를 닫을 때 LeftMenu에 있는 모든 뷰를 다 setEnable로 꺼버리고 


열 때는 켜는 식을 사용 했습니다. 


열고 닫을 때 


FrameLayout viewGroup = (FrameLayout) findViewById(R.id.ll_menuLayout)

.getParent();


이런식으로 menu  레이아웃을 잡고 


enableDisableViewGroup(viewGroup, false);


setEnable을 true 할 건지 false 할 건지 정해 주시면 됩니다. 


그럼 


 public static void enableDisableViewGroup(ViewGroup viewGroup,
            boolean enabled) {
        int childCount = viewGroup.getChildCount();
        for (int i = 0; i < childCount; i++) {
 
 
            View view = viewGroup.getChildAt(i);
            view.setEnabled(enabled);
 
            if (view instanceof ViewGroup) {
                enableDisableViewGroup((ViewGroup) view, enabled);
            }
        }
  }
 

menu레이아웃에 있는 뷰들의 갯수 만큼 for문을 돌며 각각 setEnable을 할 수 있습니다.



응용하면 좌측 슬라이드 메뉴를 열었을 때 좌측 슬라이드에 있는 다른 버튼은 눌리지 않고

LeftSlide 버튼만 눌리게 하고싶을 땐

FrameLayout viewGroup = (FrameLayout) findViewById(R.id.ll_fragment)

.getParent();


이렇게 좌측 슬라이드 메뉴 레이아웃을 잡고 


enableDisableViewGroup 매소드 for문 안쪽에


View view = viewGroup.getChildAt(i);


if (view.getId() != R.id.ib_left) {

view.setEnabled(enabled);

if (view instanceof ViewGroup) {

enableDisableViewGroup((ViewGroup) view, enabled);

}

}


이런식으로 LeftSlide 버튼만 살려서 disable을 막는 방법이 있습니다.











LeftSlideMenuExample.zip









-- 2013 10 22 내용추가 


좌 우 측 슬라이드가 모두 되는 소스 첨부 합니다. 


우측 슬라이드도 좌측 슬라이드와 같은 방식으로 만들었습니다. 





SlideMenu.zip





List of Articles
번호 제목 날짜 조회 수
237 카카오톡 분석하기 (1) - sqlite 파해치기 file 2016.05.26 10063
236 카카오톡 대화내용 가져오기(sqlite3, chat_logs) file 2016.05.26 15109
235 초기화면 페이지를 만들어보자. splash 페이지 제작 file 2020.12.14 284
234 체크 박스(CheckBox)의 이미지 바꾸기 2015.07.16 6398
233 줄바꿈 문자 치환 2020.12.14 289
232 전화 인텐트와 나의 전화 번호가져오기 2014.08.28 6312
231 인텐트를 이용한 Activity간 데이터 전달 (사용자 정의 클래스) file 2015.07.16 7061
230 이미지의 Orientation를 체크해서 이미지 회전하기 2015.07.16 7658
229 이미지 버튼(ImageButton) 만들기 2015.07.16 7114
228 이미지 버튼 설정 2015.07.16 6378
227 위젯 업데이트 주기 빠르게 하기 2018.10.02 2142
226 월별 캘린더에 일정 입력 및 조회 기능 리스트로 추가하기 file 2015.07.16 18552
225 옵션 메뉴 동적으로 생성하기 2015.07.16 6926
224 어댑터 뷰(Adapter View) & 어댑터(Adapter) (1) file 2016.06.08 7852
223 앱 번들(Android App Bundle) 만들기 file 2021.09.14 305
222 암시적 인텐트를 사용한 인터넷열기, 전화걸기, 문자보내기 [Intent (인텐트)] file 2016.06.07 7736
221 알아놓으면 좋은 내용정리 2016.06.07 7458
220 안드로이트 비콘 스캐닝시 고려 사항 2015.07.26 6658
219 안드로이드용 채팅프로그램 클라이언트(java), 서버(c#) 소스 file 2016.05.19 11720
218 안드로이드와 mysql 연동시키기. php 와 json 사용 file 2015.07.16 24486
Board Pagination Prev 1 2 3 4 5 6 7 8 9 10 ... 13 Next
/ 13

하단 정보를 입력할 수 있습니다

© k2s0o1d4e0s2i1g5n. All Rights Reserved