Comment Google a-t-il réussi à faire cela? Slide ActionBar dans l’application Android

Je veux vraiment implémenter cela (la navigation latérale) dans une application personnelle, est-ce que quelqu’un sait comment Google a réussi à le faire?

Ils semblent avoir écarté la fenêtre actuelle et mis en place une navigation aérienne.

En fait, il y a un moyen de le faire. Même sans implémenter votre propre ActionBar .

Jetez un coup d’œil à la hierachyviewer ! (Situé dans le répertoire des outils)

Il y a le DecorView , et un LinearLayout tant qu’enfant. Ce LinearLayout contient à la fois ActionBar et les autres contenus. Donc, vous pouvez simplement appliquer quelques FrameLayout.LayoutParams à ce LinearLayout et obtenir un espace sur le côté gauche de cette façon. Ensuite, vous pouvez remplir cet espace avec votre menu-ListView et superposer l’autre contenu avec un FrameLayout, qui, lorsqu’il est cliqué, réduit le menu. Donc, voici du code:

Tout d’abord, la classe de réduction / expansion (SlideMenu.java):

 package your.cool.app; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Rect; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.view.animation.TranslateAnimation; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; public class SlideMenu { //just a simple adapter public static class SlideMenuAdapter extends ArrayAdapter { Activity act; SlideMenu.SlideMenuAdapter.MenuDesc[] items; class MenuItem { public TextView label; public ImageView icon; } static class MenuDesc { public int icon; public Ssortingng label; } public SlideMenuAdapter(Activity act, SlideMenu.SlideMenuAdapter.MenuDesc[] items) { super(act, R.id.menu_label, items); this.act = act; this.items = items; } @Override public View getView(int position, View convertView, ViewGroup parent) { View rowView = convertView; if (rowView == null) { LayoutInflater inflater = act.getLayoutInflater(); rowView = inflater.inflate(R.layout.menu_listitem, null); MenuItem viewHolder = new MenuItem(); viewHolder.label = (TextView) rowView.findViewById(R.id.menu_label); viewHolder.icon = (ImageView) rowView.findViewById(R.id.menu_icon); rowView.setTag(viewHolder); } MenuItem holder = (MenuItem) rowView.getTag(); Ssortingng s = items[position].label; holder.label.setText(s); holder.icon.setImageResource(items[position].icon); return rowView; } } private static boolean menuShown = false; private static View menu; private static LinearLayout content; private static FrameLayout parent; private static int menuSize; private static int statusHeight = 0; private Activity act; SlideMenu(Activity act) { this.act = act; } //call this in your onCreate() for screen rotation public void checkEnabled() { if(menuShown) this.show(false); } public void show() { //get the height of the status bar if(statusHeight == 0) { Rect rectgle = new Rect(); Window window = act.getWindow(); window.getDecorView().getWindowVisibleDisplayFrame(rectgle); statusHeight = rectgle.top; } this.show(true); } public void show(boolean animate) { menuSize = Functions.dpToPx(250, act); content = ((LinearLayout) act.findViewById(android.R.id.content).getParent()); FrameLayout.LayoutParams parm = (FrameLayout.LayoutParams) content.getLayoutParams(); parm.setMargins(menuSize, 0, -menuSize, 0); content.setLayoutParams(parm); //animation for smooth slide-out TranslateAnimation ta = new TranslateAnimation(-menuSize, 0, 0, 0); ta.setDuration(500); if(animate) content.startAnimation(ta); parent = (FrameLayout) content.getParent(); LayoutInflater inflater = (LayoutInflater) act.getSystemService(Context.LAYOUT_INFLATER_SERVICE); menu = inflater.inflate(R.layout.menu, null); FrameLayout.LayoutParams lays = new FrameLayout.LayoutParams(-1, -1, 3); lays.setMargins(0,statusHeight, 0, 0); menu.setLayoutParams(lays); parent.addView(menu); ListView list = (ListView) act.findViewById(R.id.menu_listview); list.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { //handle your menu-click } }); if(animate) menu.startAnimation(ta); menu.findViewById(R.id.overlay).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { SlideMenu.this.hide(); } }); Functions.enableDisableViewGroup((LinearLayout) parent.findViewById(android.R.id.content).getParent(), false); ((ExtendedViewPager) act.findViewById(R.id.viewpager)).setPagingEnabled(false); ((ExtendedPagerTabSsortingp) act.findViewById(R.id.viewpager_tabs)).setNavEnabled(false); menuShown = true; this.fill(); } public void fill() { ListView list = (ListView) act.findViewById(R.id.menu_listview); SlideMenuAdapter.MenuDesc[] items = new SlideMenuAdapter.MenuDesc[5]; //fill the menu-items here SlideMenuAdapter adap = new SlideMenuAdapter(act, items); list.setAdapter(adap); } public void hide() { TranslateAnimation ta = new TranslateAnimation(0, -menuSize, 0, 0); ta.setDuration(500); menu.startAnimation(ta); parent.removeView(menu); TranslateAnimation tra = new TranslateAnimation(menuSize, 0, 0, 0); tra.setDuration(500); content.startAnimation(tra); FrameLayout.LayoutParams parm = (FrameLayout.LayoutParams) content.getLayoutParams(); parm.setMargins(0, 0, 0, 0); content.setLayoutParams(parm); Functions.enableDisableViewGroup((LinearLayout) parent.findViewById(android.R.id.content).getParent(), true); ((ExtendedViewPager) act.findViewById(R.id.viewpager)).setPagingEnabled(true); ((ExtendedPagerTabSsortingp) act.findViewById(R.id.viewpager_tabs)).setNavEnabled(true); menuShown = false; } } 

Quelques méthodes d’aide (pour moi, en Fonctions statiques.java):

  public static int dpToPx(int dp, Context ctx) { Resources r = ctx.getResources(); return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMesortingcs()); } //originally: http://stackoverflow.com/questions/5418510/disable-the-touch-events-for-all-the-views //modified for the needs here public static void enableDisableViewGroup(ViewGroup viewGroup, boolean enabled) { int childCount = viewGroup.getChildCount(); for (int i = 0; i < childCount; i++) { View view = viewGroup.getChildAt(i); if(view.isFocusable()) view.setEnabled(enabled); if (view instanceof ViewGroup) { enableDisableViewGroup((ViewGroup) view, enabled); } else if (view instanceof ListView) { if(view.isFocusable()) view.setEnabled(enabled); ListView listView = (ListView) view; int listChildCount = listView.getChildCount(); for (int j = 0; j < listChildCount; j++) { if(view.isFocusable()) listView.getChildAt(j).setEnabled(false); } } } } 

Ensuite, les mises en page:

Disposition du menu (res / layout / menu.xml)

        

Disposition des listitems (res / layout / menu_listitem.xml):

     

Comment l'utiliser:

Dans votre onCreate() :

 private SlideMenu slidemenu; @Override public void onCreate(Bundle savedInstanceState) { //your onCreate code slidemenu = new SlideMenu(this); slidemenu.checkEnabled(); } 

Dans le gestionnaire de votre bouton d'accueil ActionBar:

 slidemenu.show(); 

C'est tout!

Et maintenant, une petite capture d'écran en action:

SlideMenu

Pour autant que je sache, cela fonctionne. Si vous rencontrez des problèmes ou si mes explications ne sont pas claires, contactez-moi s'il vous plaît!

EDIT: ExtendedViewPager & ExtendedPagerSsortingp :

ExtendedViewPager:

 package your.cool.app; //source: http://blog.svpino.com/2011/08/disabling-pagingswiping-on-android.html import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AtsortingbuteSet; import android.view.MotionEvent; public class ExtendedViewPager extends ViewPager { private boolean enabled; public ExtendedViewPager(Context context, AtsortingbuteSet attrs) { super(context, attrs); this.enabled = true; } @Override public boolean onTouchEvent(MotionEvent event) { if (this.enabled) { return super.onTouchEvent(event); } return false; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (this.enabled) { return super.onInterceptTouchEvent(event); } return false; } public void setPagingEnabled(boolean enabled) { this.enabled = enabled; } } 

ExtendedPagerTabSsortingp:

 package your.cool.app; //source: http://blog.svpino.com/2011/08/disabling-pagingswiping-on-android.html import android.content.Context; import android.support.v4.view.PagerTabSsortingp; import android.util.AtsortingbuteSet; import android.view.MotionEvent; public class ExtendedPagerTabSsortingp extends PagerTabSsortingp { private boolean enabled; public ExtendedPagerTabSsortingp(Context context, AtsortingbuteSet attrs) { super(context, attrs); this.enabled = true; } @Override public boolean onTouchEvent(MotionEvent event) { if (this.enabled) { return super.onTouchEvent(event); } return false; } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (this.enabled) { return super.onInterceptTouchEvent(event); } return false; } public void setNavEnabled(boolean enabled) { this.enabled = enabled; } } 

J'utilise ce SlideMenu pour une activité avec un ViewPager avec PagerTabSsortingp pour des tabs tels que Talk, Market, etc. Vous ne pouvez pas désactiver ces vues d'une manière simple.

Il y a plusieurs tentatives pour le faire, mais je n’ai pas encore trouvé de code source ou de code source sur la façon de l’implémenter avec une barre d’action à tous les niveaux de l’API. Une lib prometteuse est ici

https://github.com/jfeinstein10/SlidingMenu

voici une vidéo de l’ application exemple .

Voici le lien de l’application Google Play .

Cela fonctionne avec ActionbarSherlock. Vous devrez construire la bibliothèque SlidingMenu avec ABS pour la faire fonctionner. Fonctionne et a fière allure!

A fait un tour d’horizon de l’ implémentation d’origine et ajouté l’parsing syntaxique XML ainsi que l’ autodetection d’une barre d’action éventuellement présente, elle fonctionne donc avec la barre d’action native ainsi que la barre d’action, comme ActionBarSherlock .

Le tout est maintenant un projet de bibliothèque avec un exemple d’application et est décrit dans Sliding Menu pour android Merci à scirocco pour l’idée initiale et le code!

Capture d'écran de LibSlideMenu

Si vous utilisez un niveau d’API supérieur à 11, vous pouvez utiliser une approche beaucoup plus simple inspirée de la réponse donnée par @Scirocco

 // get content parent that is basically the whole // app screen (viewed from hierarchy viewer) final LinearLayout content = (LinearLayout) findViewById(android.R.id.content).getParent(); // make new value animator with range from 0 to 1 final ValueAnimator animator = ValueAnimator.ofFloat(0, 1); // set custom duration animator.setDuration(500); // on update is called for every value in the // given range in time frame defined by the duration animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { // get the current value float value = ((Float) (animation.getAnimatedValue())).floatValue(); // translate by that value, minus means translate left content.setTranslationX(-250 * value); } }); // start the animator animator.start(); // make or inflate custom view for test purposes Button textView = new Button(this); textView.setText("TestButton"); // add it to the frame layout that is the parent of the content on position 0 FrameLayout parent = (FrameLayout) content.getParent(); parent.addView(textView, 0); 

L’idée ici est d’utiliser ValueAnimator qui transforme et pas seulement anime la mise en page principale avec la barre d’action, de sorte que vous pouvez interagir avec la vue gonflée que vous souhaitez utiliser comme panneau coulissant. Vous devez remplacer les valeurs codées en dur par quelque chose d’utile pour votre application.

J’espère que ça aide 🙂

Eh bien, je suis en train de travailler sur un projet et je suis tombé sur le menu Sliding, mais j’ai été très déçu de voir que personne n’a donné un morceau de code ou un indice sur la façon de créer un menu glissant. Les projets / bibliothèques de github à utiliser, j’ai décidé de le faire moi-même et finalement j’ai mon propre menu coulissant prêt …

J’ai passé deux jours dessus

1. en faisant des animations de glissement

2. pour le faire fonctionner avec toutes les résolutions d’écran

C’est vraiment simple et facile une fois que vous avez une idée sur les animations , j’ai lu certaines, ce n’est pas raisonnable de réinventer la roue (les gens qui se réfèrent au code source du menu glissant), mais je pense que vous devriez essayez de faire les vôtres pour avoir une idée de son fonctionnement et de son fonctionnement: P

c’est donc une image de la façon dont mon menu coulant va fonctionner

1.Find.xml //later in the code it will be refer as findLayout

                   //here i included the filter.xml, which is on top of find.xml layout and is initially invisible  

entrer la description de l'image ici

2.Filter.xml //later in code refer as FilterLayout

                              

entrer la description de l'image ici

Dans find.xml, j’ai inclus initialement filter.xml qui est invisible

Maintenant FilterAnimation.java

 package matchat.helpers; import com.s3.matchat.R; import android.content.Context; import android.util.DisplayMesortingcs; 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; DisplayMesortingcs displayMesortingcs = context.getResources().getDisplayMesortingcs(); deviceWidth = displayMesortingcs.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); } } 

Maintenant 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.DisplayMesortingcs; 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); DisplayMesortingcs displayMesortingcs = getResources().getDisplayMesortingcs(); int deviceWidth = displayMesortingcs.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; } } } 

Voici les animations res / anim

1.filter_slide_in.xml

     

2.filter_slide_out.xml

     

3.other_slide_in.xml

     

4.other_slide_out.xml

     

Vous y trouverez un menu coulissant fonctionnel et fonctionnel, et vous pourrez le personnaliser en fonction de vos besoins. Si vous rencontrez encore des problèmes lors de la configuration, n’hésitez pas à demander, je suis ravi de vous aider 🙂

J’ai créé ma propre solution pour faire disparaître la vue et révéler un menu en dessous, car de nombreuses autres solutions semblaient ne pas fonctionner sur les anciennes versions d’Android ou ne disposaient pas des instructions appropriées pour le faire fonctionner.

Ma solution présente les fonctionnalités suivantes:

  • Fournit un support pour faire glisser une vue pour révéler un menu qui se trouve en dessous
  • Le menu et la vue ci-dessus peuvent être des vues personnalisées.
  • Pris en charge sur les anciennes versions d’Android (testé pour fonctionner au moins sous Android 2.2)
  • Fonctionne avec les projets PhoneGap / Cordova

La solution utilise une disposition personnalisée, appelée SlidingMenuLayout, à laquelle vous devez append 2 vues. La première vue que vous ajoutez est le menu, la seconde est la vue principale.

La méthode la plus simple pour append la mise en page à votre projet existant consiste à remplacer la méthode setContentView() votre activité:

 @Override public void setContentView(View view) { SlidingMenuLayout layout = new SlidingMenuLayout(this); layout.setLayoutParams(new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0F)); layout.addView(new MenuView(this)); layout.addView(view); super.setContentView(layout); } 

Dans cet exemple, MenuView est la vue qui affichera réellement le menu. C’est à vous d’implémenter cette vue.
Enfin, vous pouvez append un bouton (généralement situé dans le coin supérieur gauche de votre vue principale), qui appelle openMenu() ou closeMenu() dans la présentation, selon le cas.
Le code de SlidingMenuLayout se trouve sur la page du projet GitHub.

Pour ceux d’entre vous qui utilisent la bibliothèque SlidingMenu ( https://github.com/jfeinstein10/SlidingMenu ), il existe un moyen de le twigr et cela semble fonctionner! Avec l’aide de @Scirocco, mettez ceci dans votre onCreate pour l’activité:

 ViewGroup decorView = (ViewGroup) getWindow().getDecorView(); mSlidingMenu = new SlidingMenu(this); ViewGroup mainContent = (ViewGroup) decorView.getChildAt(0); decorView.removeView(mainContent); mSlidingMenu.setContent(mainContent); decorView.addView(mSlidingMenu); mMenu = (LinearLayout) View.inflate(this, R.layout.menuview, null); mSlidingMenu.setMenu(mMenu); mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN); mSlidingMenu.setBehindOffsetRes(R.dimen.slidingmenu_offset); 

en gros, il remplace le linearlayout dans la vue décor par le slidingmenu .

Remarque: je l’ai seulement testé légèrement mais il semble fonctionner.

  public class ImprovedSlidingPaneLayout extends SlidingPaneLayout { Context context; FrameLayout left; FrameLayout right; Boolean canOpen = true; public ImprovedSlidingPaneLayout(Context context) { super(context); this.context = context; this.left = new FrameLayout(context); this.right = new FrameLayout(context); this.addView(left); this.addView(right); } public ImprovedSlidingPaneLayout(Context context, AtsortingbuteSet attrs) { super(context, attrs); this.context = context; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (canOpen) return super.onInterceptTouchEvent(ev); else return false; } public ImprovedSlidingPaneLayout canOpen(Boolean canOpen) { this.canOpen = canOpen; return this; } public ImprovedSlidingPaneLayout makeActionBarSlide(Window window){ ViewGroup decorView = (ViewGroup) window.getDecorView(); ViewGroup mainContent = (ViewGroup) decorView.getChildAt(0); decorView.removeView(mainContent); setContentView(mainContent); decorView.addView(this); return this; } public ImprovedSlidingPaneLayout setMenuView(View view){ if((left.getChildCount()== 1)){ left.removeView(left.getChildAt(0)); } left.addView(view); return this; } public ImprovedSlidingPaneLayout setContentView(View view){ if((right.getChildCount()== 1)){ right.removeView(right.getChildAt(0)); } right.addView(view); return this; } public ImprovedSlidingPaneLayout setMenuWidth(int width){ left.setLayoutParams(new SlidingPaneLayout.LayoutParams(width, ViewGroup.LayoutParams.MATCH_PARENT)); return this; } } 

c’est ma classe qui étend SlidingPaneLayout . Peut glisser avec actio