Connect SlidingMenu to the Support Library and work around possible problems

Foreword


Hello, Habr!

Immediately I want to make a small digression from the topic: I am not a professional android developer and just learning. In this post, designed more for beginners, I would like to combine solutions to the problems that I encountered when writing a conceived application, in particular using the ActionBar with the Support Library and attaching SlidingMenu to them.

Examples of quality for me are VK, Forsquare, and Instagram. Actually, ideas for using ActionBar and SlidingMenu were immediately taken from them. As with the layout / development of web sites (my main business) and their decent work in Internet Explorer, here, I first thought about compatibility with older versions of Android, since ActionBar is only supported with 3.0. Thanks to the search, I quickly found a solution - ActionBar for versions 2.1+ .


Let's start


1. Create a new project in Eclipse. How to do this can be found using the search for Habrahabr. The minimum supported version is API 7. Preferably, without a theme (Theme: None).
2. We connect the Support Library, how to do this, is written at the link above. Here again, just in case. We write the topic.
3. This is the first problem I had to face: everything works fine on Android below 3.0. It turns out that one point is not specified in the article above: the topic is proposed to be inherited in the file res / values ​​/ styles.xml However, this turned out to be not the most correct option. When creating a project, Eclipse immediately creates several style files for different versions of the API:

  • res / values ​​/ styles.xml - standard style file;
  • res / values-v11 / styles.xml - stylesheet for API 11+;
  • and res / values-v14 / styles.xml - the stylesheet for API 14+;

We inherit the theme only in the first of the above files, therefore it only works up to version Android 3.0 (API11).
It is solved by inheritance of the theme in all files or directly in the project manifest. To do this, go to AndroidManifest.xml and find the lines:
<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

where we replace:
android:theme="@style/AppTheme"

on the:
android:theme="@style/Theme.AppCompat.Light"


If there is no line android: theme - add it.
In this case, it is worth remembering that when inheriting a topic directly in the manifest, you cannot use your color scheme, so I recommend using the first option, with inheritance in each file separately.

This problem took 2 days, the solution of which was found when searching for information on a completely different topic.

Run, check. Everything is working.


Connect SlidingMenu

In the process of searching for such a menu, I immediately came across Drawer . However, this was not what I needed, for some reason, which I will not describe here.
The choice fell on SlidingMenu. The library is completely free and available on GitHub .

1. Download all the files and start connecting to Eclipse: for this, go to File → New → Other → Android Project from Existing Code , in the window that opens, specify the path to the library folder of the previously downloaded SlidingMenu. After the files are copied, click OK. The library is connected.
2. We connect it to our project created earlier. Repeat the connection procedure Support Lirary, but this time select "library".
3. And here is the second problem - the console reports a conflict of two files android-support-v4.jar . It turned out that this file is small, which is contained in the project itself, so the Support Library and SlidingMenu are also connected. The solution turned out to be simple, it was found on StackOverflow.com: we delete this file from the SlidingMenu library and from our project (both have it in the “lib” folder).
Now a new problem has arisen - the SlidingMenu library reports a lot of errors. This is due to the lack of a file we deleted. A workaround for this was also found on StackOverflow: we disconnect the Support Lib library from our project and connect it, but to the SlidingMenu library. In this case, the file necessary for all three will be connected first to the SlidingMenu library, and SlidingMenu, together with its functionality, will also connect Support Lib to our project.

In the comments The problem was described in a more technical language and suggested a simple solution: “You had problems with the older version of the support library in SlidingMenu and a message about different hash sums falling into the console, it was enough to copy the lib from the main project and drop it into SlidingMenu . ”

It took 3 days to solve this problem (yes, I like to spoil my life), simply because I did not pay attention to errors in the console.
It is difficult, but if you understand these nuances, everything becomes quite clear and logical.
To avoid red embarrassment, we clear the console.

After all of the above, go to MainActivity.java and declare a variable before the onCreate () method:
private SlidingMenu menu;

Next, add the menu initializer directly to onCreate:
  
menu = new SlidingMenu(this);
menu.setMode(SlidingMenu.LEFT);
menu.setTouchModeBehind(SlidingMenu.TOUCHMODE_FULLSCREEN);
menu.setShadowDrawable(R.drawable.slidemenu_shadowgradient);
menu.setShadowWidth(15);
menu.setFadeDegree(0.0f);
menu.attachToActivity(this, SlidingMenu.SLIDING_WINDOW);
menu.setBehindWidth(200);
menu.setMenu(R.layout.menu_frame);

As you can see in the code, the paths to the file with the shadow ( menu.setShadowDrawable (R.drawable. Slidemenu_shadowgradient ) ) and, in fact, the menu itself ( menu.setMenu (R.layout. Menu_frame ) ) are indicated . These files must be created. Examples of all sources under the spoiler below.

Source code
MainActivity.java

import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity {
	
	private SlidingMenu menu;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		menu = new SlidingMenu(this);
		menu.setMode(SlidingMenu.LEFT);
		menu.setTouchModeBehind(SlidingMenu.TOUCHMODE_FULLSCREEN);
		menu.setShadowDrawable(R.drawable.aslidingmenu_shadowgradient);
		menu.setShadowWidth(15);
		menu.setFadeDegree(0.0f);
		menu.attachToActivity(this, SlidingMenu.SLIDING_WINDOW);
		menu.setBehindWidth(200);
		menu.setMenu(R.layout.menu_frame);
	}
}



res / drawable / slidingmenu_shadowgradient.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
    <shape>
	    <gradient
	        android:endColor="@color/purple_dark"
	       android:startColor="@color/back" />  
    </shape>
</item>
</selector>



res / layout / menu_frame.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:background="@color/back">
 
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/menu_1"
        android:textAppearance="?android:attr/textAppearanceLarge" />
 
    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/menu_2"
        android:textAppearance="?android:attr/textAppearanceLarge" />
 
    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/menu_3"
        android:textAppearance="?android:attr/textAppearanceLarge" />
 
    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/menu_4"
        android:textAppearance="?android:attr/textAppearanceLarge" />
 
</LinearLayout>



res / values ​​/ strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">SlideMenu Demo</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>

    <color name="back">#3d4140</color>
    <color name="purple_light">#ffffff</color> 
    <color name="purple_dark">#353838</color> 
    <string name="menu_1">Menu 1</string> 
    <string name="menu_2">Menu 2</string> 
    <string name="menu_3">Menu 3</string> 
    <string name="menu_4">Menu 4</string>
    
</resources>




Add functionality

All that is described above is certainly good, but some details are lacking. For example, using the VK application, you often have to resort to the side menu (SlidingMenu). I push it with the movement of a finger across the screen, but there are several different ways to open it.

Icon in ActionBar

To add functionality to the button-icon in the action bar, we use the following code, which is placed anywhere in MainActivity.java :

@Override
	public boolean onOptionsItemSelected(MenuItem item) {
	    switch (item.getItemId()) {  // узнаем ID нажатой кнопки
	    case android.R.id.home: // если это кнопка-иконка ActionBar,
	    	menu.toggle(true);        // открываем меню (или закрываем)
	        return true;
	    }
	    return super.onOptionsItemSelected(item);
	}

At the end of onCreate (), add:
getSupportActionBar().setDisplayShowCustomEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);

Among other things, the last code adds a beautiful arrow to the icon.

Closing the menu by pressing the "Back" button

Everything is simple here, the menu is open, but when you click "Back" the application closes, not the menu. We fix it with the following code:

public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) { // если нажата кнопка "Назад"
			if(menu.isMenuShowing()){ // и если SlidingMenu открыто
        		menu.toggle(true); // закрываем его
                        return false;
        	        }
                 }
	         return super.onKeyDown(keyCode, event);
}

In the comments также предложили использовать onBackPressed()

Full code MainActivity.java

import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends ActionBarActivity {
	
	private SlidingMenu menu;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		menu = new SlidingMenu(this);
		menu.setMode(SlidingMenu.LEFT);
		menu.setTouchModeBehind(SlidingMenu.TOUCHMODE_FULLSCREEN);
		menu.setShadowDrawable(R.drawable.actionbar_gradient);
		menu.setShadowWidth(15);
		menu.setFadeDegree(0.0f);
		menu.attachToActivity(this, SlidingMenu.SLIDING_WINDOW);
		menu.setBehindWidth(200);
		menu.setMenu(R.layout.menu_frame);
		
		getSupportActionBar().setDisplayShowCustomEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
	    switch (item.getItemId()) {
	    case android.R.id.home:
	    	menu.toggle(true);
	        return true;
	    }
	    return super.onOptionsItemSelected(item);
	}
	
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK) {
			if(menu.isMenuShowing()){
        		menu.toggle(true);
                        return false;
        	        }
                }
	        return super.onKeyDown(keyCode, event);
	}

}



Result:
(unfortunately, this screen did not load completely on HabraStorage, I had to use third-party image hosting).

In conclusion


I will answer a logical question that may arise from the reader: “Why not an ActionBar Sherlock” (if you certainly know what it is)?
The answer is simple: I did not know about its existence at the beginning of the work. When SlidingMenu started, I found out about the recommended sherlock, but there was no desire to change Support Lib and half the code with it.

As it turned out, starting programming for Android is not so easy, given that half of the problems are not connected with this platform at all, but with tools for it.
But, as I said above, you only need to figure it out a bit and then everything becomes much clearer.

Thank you if you read to the end.

P.S. If you have comments on the quality of the code or the quality of the text - express, but do not forget, please, that everything is designed for beginners from the same beginner.

UPD: Added comments from comments.