메뉴 건너뛰기

조회 수 12536 추천 수 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 안드로이드 - 익명 클래스(Anonymous Class) 사용법 file 2021.03.31 281
236 안드로이드 - 문자열 리소스를 활용한 다국어 지원 file 2021.03.31 282
235 안드로이드 - SnackBar를 사용해 팝업창 띄우기 file 2021.03.31 282
234 안드로이드 - 옵션 메뉴 (Option Menu) 구현 방법 file 2021.04.01 283
233 초기화면 페이지를 만들어보자. splash 페이지 제작 file 2020.12.14 285
232 Java에서 XML 불러와서 동적 변화 주기 file 2021.03.31 288
231 줄바꿈 문자 치환 2020.12.14 289
230 [하이브리드앱] 링크를 웹뷰가 아닌 새로운 브라우저에서 열기 2021.09.30 293
229 패키지명을 한꺼번에 변경하기 (Refactor) file 2020.12.14 295
228 앱 번들(Android App Bundle) 만들기 file 2021.09.14 305
227 android.support.v4.content.FileProvider not found file 2020.12.14 308
226 안드로이드 - 리니어 레이아웃 (Linear Layout) file 2021.03.29 319
225 안드로이드 - 토스트(Toast) 메시지 사용하기. file 2021.03.31 321
224 안드로이드 - 뷰페이저(ViewPager) 구현 file 2021.04.02 323
223 안드로이드 앱배포하기 apk 만들기 file 2020.12.14 324
222 안드로이드 - 명시적 인텐트(Explicit Intent)와 암시적 인텐트 (Implicit Intent) file 2021.04.01 324
221 안드로이드 arrayList 를 Json으로 변환 / jsonarry file 2021.03.29 326
220 Firebase - 푸시알림 보내기 file 2021.09.30 339
219 Volley 이용시에 한글 깨질때 UTF-8로 변경 2020.12.14 343
218 안드로이드 - 버튼 이벤트 처리방법 정리 (리스너 구현 및 이벤트 핸들링) file 2021.03.31 343
Board Pagination Prev 1 2 3 4 5 6 7 8 9 10 ... 13 Next
/ 13

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

© k2s0o1d4e0s2i1g5n. All Rights Reserved