Android – 如何制作像facebook,spotify和Google +的幻灯片菜单
我想添加一个幻灯片菜单到我的应用程序,如Facebook应用程序。 我在互联网上阅读了很多有关图书馆的东西,但都没有为我工作。 什么是最好的东西/图书馆,我可以用这个,也可以有人可以解释我如何使用它?
编辑这是我的布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@drawable/zwemfest" >" <com.devspark.sidenavigation.SideNavigationView android:id="@+id/side_navigation_view" android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/button1" android:layout_width="183dp" android:layout_height="113dp" android:layout_weight="0.91" android:text="Button" /> </com.devspark.sidenavigation.SideNavigationView> </RelativeLayout>
但是我没有看到任何button或背景图像。 你知道怎么回事?
那么目前我正在做一个项目,并遇到滑动菜单,我GOOGLE了,但失望的看到,没有人已经给出了一些指示或提示如何开始做一个滑动菜单,每个人已经链接到一些Github的项目/图书馆使用,因此,我决定自己做,最后我有我自己的滑动菜单准备…
我花了两天的时间
1.制作滑动animation
2.使其适用于所有屏幕分辨率
一旦你对animation有了一些想法,它真的很容易和简单,我已经阅读了一些地方,它不是重新发明轮子 (指的是滑动菜单的github源代码的人),但我相信你至less应该一旦尝试做出自己的想法,那么你就会明白它是如何工作和运作的:P
所以这是我的滑动菜单将如何工作的图片
1.Find.xml //later in the code it will be refer as findLayout
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <RelativeLayout android:id="@+id/find_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/header" android:layout_width="match_parent" android:layout_height="60dp" android:padding="2dp" android:background="@drawable/main_header"> <Button android:id="@+id/filter" android:layout_width="40dp" android:layout_height="30dp" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:background="@drawable/filter_button" /> <TextView android:id="@+id/city" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/filter" android:layout_marginLeft="20dp" android:layout_marginTop="3dp" android:text="Islamabad" android:textSize="22sp" android:textStyle="bold" android:textColor="@android:color/primary_text_dark"/> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/city" android:layout_alignLeft="@+id/city"> <TextView android:id="@+id/interested_in" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:text="Men and Women" android:textSize="12sp" android:textColor="@android:color/primary_text_dark"/> <ImageView android:id="@+id/separator" android:layout_width="2dp" android:layout_height="18dp" android:layout_toRightOf="@+id/interested_in" android:layout_marginLeft="4dp" android:src="@drawable/separator_1" android:layout_centerVertical="true" /> <TextView android:id="@+id/age" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:layout_toRightOf="@+id/separator" android:layout_centerVertical="true" android:text="18-24 years" android:textSize="12sp" android:textColor="@android:color/primary_text_dark"/> <ImageView android:id="@+id/separator_1" android:layout_width="2dp" android:layout_height="18dp" android:layout_toRightOf="@+id/age" android:layout_marginLeft="4dp" android:src="@drawable/separator_1" android:layout_centerVertical="true" /> <TextView android:id="@+id/distance" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:layout_toRightOf="@+id/separator_1" android:layout_centerVertical="true" android:text=">30km" android:textSize="12sp" android:textColor="@android:color/primary_text_dark"/> </RelativeLayout> </RelativeLayout> <GridView android:id="@+id/users_grid" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/header" android:numColumns="4"> </GridView> </RelativeLayout> <include layout="@layout/filter"/> //here i included the filter.xml, which is on top of find.xml layout and is initially invisible </RelativeLayout>
2.Filter.xml //later in code refer as FilterLayout
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/filter_layout" android:visibility="invisible" android:layout_width="260dp" android:layout_height="match_parent" android:background="@drawable/grey_bg" > <ImageView android:id="@+id/profile_pic" android:layout_width="match_parent" android:layout_height="220dp" android:src="@drawable/pic"/> <RelativeLayout android:id="@+id/header" android:layout_width="match_parent" android:layout_height="55dp" android:paddingLeft="10dp" android:paddingTop="5dp" android:layout_below="@+id/profile_pic" android:background="@drawable/light_blue_header"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="3dp" android:text="Raja Babar" android:textSize="18sp" android:textStyle="bold" android:textColor="@android:color/primary_text_dark"/> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/name" android:layout_alignLeft="@+id/name"> <TextView android:id="@+id/gender" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:text="Male" android:textSize="12sp" android:textColor="@android:color/primary_text_dark" /> <ImageView android:id="@+id/seperator" android:layout_width="2dp" android:layout_height="20dp" android:layout_toRightOf="@+id/gender" android:layout_marginLeft="5dp" android:src="@drawable/separator_1" android:layout_centerVertical="true" /> <TextView android:id="@+id/age" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/seperator" android:layout_marginLeft="5dp" android:layout_centerVertical="true" android:text="22 years" android:textSize="12sp" android:textColor="@android:color/primary_text_dark" /> </RelativeLayout> </RelativeLayout> <ScrollView android:layout_width="250dp" android:layout_height="wrap_content" android:layout_below="@+id/header" android:layout_marginTop="15dp" android:layout_centerHorizontal="true"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/filter_options" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/filter_options" android:textSize="18sp" android:textStyle="bold" android:textColor="@android:color/primary_text_light"/> <RelativeLayout android:id="@+id/interested_in_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="15dp" android:paddingRight="40dp" android:layout_below="@+id/filter_options" android:background="@drawable/interested_in_field"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:text="@string/gender" android:textSize="18sp" android:textStyle="bold" android:textColor="@android:color/primary_text_light"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:text="@string/women_men" android:textSize="18sp" android:textColor="#33b9cd" /> </RelativeLayout> <RelativeLayout android:id="@+id/age_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="15dp" android:paddingRight="40dp" android:layout_below="@+id/interested_in_layout" android:background="@drawable/age_field_1"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:text="@string/age" android:textSize="18sp" android:textStyle="bold" android:textColor="@android:color/primary_text_light"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:text="18-24 years" android:textSize="18sp" android:textColor="#33b9cd"/> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="15dp" android:paddingRight="40dp" android:layout_below="@+id/age_layout" android:background="@drawable/distance_field"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:text="@string/distance" android:textSize="18sp" android:textStyle="bold" android:textColor="@android:color/primary_text_light"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:text=">30km" android:textSize="18sp" android:textColor="#33b9cd"/> </RelativeLayout> </RelativeLayout> </ScrollView> </RelativeLayout>
在find.xml中,我最初包含了不可见的filter.xml
现在FilterAnimation.java
package matchat.helpers; import com.s3.matchat.R; import android.content.Context; import android.util.DisplayMetrics; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; import android.widget.RelativeLayout; public class FilterAnimation implements AnimationListener { Context context; RelativeLayout filterLayout, otherLayout; private Animation filterSlideIn, filterSlideOut, otherSlideIn, otherSlideOut; private static int otherLayoutWidth, otherLayoutHeight; private boolean isOtherSlideOut = false; private int deviceWidth; private int margin; public FilterAnimation(Context context) { this.context = context; DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); deviceWidth = displayMetrics.widthPixels; // as my animation is x-axis related so i gets the device width and will use that width,so that this sliding menu will work fine in all screen resolutions } public void initializeFilterAnimations(RelativeLayout filterLayout) { this.filterLayout = filterLayout; filterSlideIn = AnimationUtils.loadAnimation(context, R.anim.filter_slide_in); filterSlideOut = AnimationUtils.loadAnimation(context, R.anim.filter_slide_out); } public void initializeOtherAnimations(RelativeLayout otherLayout) { this.otherLayout = otherLayout; otherLayoutWidth = otherLayout.getWidth(); otherLayoutHeight = otherLayout.getHeight(); otherSlideIn = AnimationUtils.loadAnimation(context, R.anim.other_slide_in); otherSlideIn.setAnimationListener(this); otherSlideOut = AnimationUtils.loadAnimation(context, R.anim.other_slide_out); otherSlideOut.setAnimationListener(this); } public void toggleSliding() { if(isOtherSlideOut) //check if findLayout is already slided out so get so animate it back to initial position { filterLayout.startAnimation(filterSlideOut); filterLayout.setVisibility(View.INVISIBLE); otherLayout.startAnimation(otherSlideIn); } else //slide findLayout Out and filterLayout In { otherLayout.startAnimation(otherSlideOut); filterLayout.setVisibility(View.VISIBLE); filterLayout.startAnimation(filterSlideIn); } } @Override public void onAnimationEnd(Animation animation) { if(isOtherSlideOut) //Now here we will actually move our view to the new position,because animations just move the pixels not the view { RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(otherLayoutWidth, otherLayoutHeight); otherLayout.setLayoutParams(params); isOtherSlideOut = false; } else { margin = (deviceWidth * 80) / 100; //here im coverting device percentage width into pixels, in my other_slide_in.xml or other_slide_out.xml you can see that i have set the android:toXDelta="80%",so it means the layout will move to 80% of the device screen,to work across all screens i have converted percentage width into pixels and then used it RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(otherLayoutWidth, otherLayoutHeight); params.leftMargin = margin; params.rightMargin = -margin; //same margin from right side (negavite) so that our layout won't get shrink otherLayout.setLayoutParams(params); isOtherSlideOut = true; dimOtherLayout(); } } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationStart(Animation animation) { } private void dimOtherLayout() { AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.5f); alphaAnimation.setFillAfter(true); otherLayout.startAnimation(alphaAnimation); } }
现在Find.java
package main.matchat.activities; import matchat.helpers.FilterAnimation; import com.s3.matchat.R; import android.app.Activity; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewTreeObserver; import android.view.View.OnClickListener; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.Button; import android.widget.RelativeLayout; public class Find extends Activity implements OnClickListener { RelativeLayout filterLayout, findLayout; Button btFilter; FilterAnimation filterAnimation; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.find); filterLayout = (RelativeLayout)findViewById(R.id.filter_layout); findLayout = (RelativeLayout)findViewById(R.id.find_layout); btFilter = (Button)findViewById(R.id.filter); btFilter.setOnClickListener(this); filterAnimation = new FilterAnimation(this); initializeAnimations(); } private void initializeAnimations() { //Setting GlobolLayoutListener,when layout is completely set this function will get called and we can have our layout onbject with correct width & height,else if you simply try to get width/height of your layout in onCreate it will return 0 final ViewTreeObserver filterObserver = filterLayout.getViewTreeObserver(); filterObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { filterLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); int deviceWidth = displayMetrics.widthPixels; int filterLayoutWidth = (deviceWidth * 80) / 100; //here im coverting device percentage width into pixels, in my other_slide_in.xml or other_slide_out.xml you can see that i have set the android:toXDelta="80%",so it means the layout will move to 80% of the device screen,to work across all screens i have converted percentage width into pixels and then used it RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(filterLayoutWidth, RelativeLayout.LayoutParams.MATCH_PARENT); filterLayout.setLayoutParams(params);//here im setting the layout params for my filter.xml because its has width 260 dp,so work it across all screen i first make layout adjustments so that it work across all screens resolution filterAnimation.initializeFilterAnimations(filterLayout); } }); final ViewTreeObserver findObserver = findLayout.getViewTreeObserver(); findObserver.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { findLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); filterAnimation.initializeOtherAnimations(findLayout); } }); } @Override public void onClick(View v) { int id = v.getId(); switch(id) { case R.id.filter: filterAnimation.toggleSliding(); break; } } }
这里是animationres / anim
1.filter_slide_in.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/decelerate_interpolator"> <translate android:fromXDelta="-100%" android:toXDelta="0%" android:duration="1000" android:fillEnabled="true" /> </set>
2.filter_slide_out.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/decelerate_interpolator"> <translate android:fromXDelta="0%" android:toXDelta="-100%" android:duration="1000"/> </set>
3.other_slide_in.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/decelerate_interpolator" > <translate android:fromXDelta="0%" android:toXDelta="-80%" android:duration="1000" android:fillEnabled="true"/> </set>
4.other_slide_out.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/decelerate_interpolator"> <translate android:fromXDelta="0%" android:toXDelta="80%" android:duration="1000" android:fillEnabled="true"/> </set>
在这里你可以find一个完整的工作和function滑动菜单,你可以定制它来满足你的要求,如果任何人仍然有一些设置问题,随时问,我很乐意帮助你🙂
https://github.com/johnkil/SideNavigation
这些日子我一直在使用这个库,它工作得很好。 事实上,它的使用非常简单。
您只需在菜单文件夹下声明一个side_navigation.xml:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/side_navigation_menu_chart" android:icon="@drawable/icon_kitsch_gray" android:title="@string/navigation_chart"/> <item android:id="@+id/side_navigation_menu_info" android:icon="@drawable/ic_menu_info_details" android:title="@string/navigation_info"/> <item android:id="@+id/side_navigation_menu_gallery" android:icon="@drawable/ic_menu_gallery" android:title="@string/navigation_photos"/> <item android:id="@+id/side_navigation_menu_signin" android:icon="@drawable/ic_menu_login" android:title="@string/navigation_signin"/> <item android:id="@+id/side_navigation_menu_settings" android:icon="@drawable/ic_menu_preferences" android:title="@string/navigation_settings"/> </menu>
然后,在您的活动布局中,添加导航视图:
<com.devspark.sidenavigation.SideNavigationView android:id="@+id/side_navigation_view" android:layout_width="match_parent" android:layout_height="match_parent" />
而且,在你的活动中,你可以链接他们两个:
SideNavigationView sideNavigationView = (SideNavigationView)findViewById(R.id.side_navigation_view); sideNavigationView.setMenuItems(R.menu.side_navigation);
编辑:
要触发侧面导航面板,当用户按下ActionBar中的主页图标时,是一个很好的select。 例如:
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: sideNavigationView.toggleMenu(); return true; default: return super.onOptionsItemSelected(item); } }
您也可以使用www.scringo.com 。 这是一个SDK,允许您添加这种types的侧边菜单几乎只是这段代码:
Scringo scringo = new Scringo(); scringo.init();
以后可以从网站上进行很多configuration(菜单方向,颜色等),还可以在菜单中添加内置function,例如收件箱,查找/邀请朋友,雷达等。
使用正式版本。 Google在I / O 2013发布了导航抽屉模式,并更新了版本4支持库以包含此function。 🙂
http://developer.android.com/design/patterns/navigation-drawer.html
下面是我开发的一个简单的滑动菜单,在github中检查项目,实现起来很简单http://github.com/leonardosalles/shipp-sliding-menu
你可以阅读这3篇文章:
http://android.cyrilmottier.com/?p=658
http://android.cyrilmottier.com/?p=701
http://android.cyrilmottier.com/?p=717
得到一个想法:)
导航抽屉(Google+与YouTube)
幻灯片菜单技术实施
侧面导航现在包含在Android SDK中。 http://developer.android.com/design/patterns/navigation-drawer.html
在github快速search确实揭示了一个已经实现了UI模式的项目。
github上的android-fb-like-slideout-navigation还有一个video展示了工作中的库。
编辑:这是另一个图书馆项目: https : //github.com/darvds/RibbonMenu谢谢BuBBLs在评论!
更多图书馆项目:
- https://bitbucket.org/jfeinstein10/slidingmenu/overview
- https://github.com/Gregadeaux/android-fly-in-app-navigation
- http://simonvt.github.io/android-menudrawer/
Cyril Mottier也在他的博客中写了关于实现这种模式的文章。 这些post非常值得一读:
- Prixing#1:Fly-in应用程序菜单的制作
- Prixing#2的制作:轻扫飞入应用程序菜单
- Prixing#3的制作:抛光滑动应用程序菜单
另请参阅Google Play上的Prixing应用,试用Cyril实施的侧面导航。
如果你想制作自己的滑动菜单,而不是使用其他库,为了更好地理解事情的工作方式,请阅读我的文章
在Android教程上创build自己的滑动菜单 – 第1部分
在Android教程上制作自己的滑动菜单 – 第2部分
要实现滑动效果,您可以移动菜单或内容视图,或两者都取决于您的愿望。
Te的想法是依靠2个方法offsetLeftAndRight()和layout()来更新视图的位置。 你还需要Scroller来促进animation
试试这个方法。 在xml中有两个相对的布局。
CONTENT(initially gone) HEADER
标题最初占据了所有的宽度,内容在标题的左边,但是当前被设置为可见性= GONE。
所以当单击标题或页眉布局上的任何button时发生点击
只需将您的内容布局的宽度设置为screen_width / 2(分数将取决于您的要求)。
public void onCreate(){ RelativeLayout header=(RelativeLayout)findViewById(R.id.header); RelativeLayout content=(RelativeLayout)findViewById(R.id.content); Display display = getWindowManager().getDefaultDisplay(); int width = display.getWidth(); // deprecated int height = display.getHeight(); // deprecated //on some event content.setVisibility(View.VISIBLE); //margin(left,right,bottom,top) content.setMargin(width/3,0,0,0); //if already opened,close the door content.setVisibility(View.GONE); }
如果你想要一些好的开放animation,在布局上使用翻译animation。
并且请确保在我的答案的顶部提到两个相对并排的初始configuration。