
Smarthome App #4: Menüpunkte auswählen
Im letzten Teil des Tutorials wurde sich um das Hauptmenü der App gekümmert. Dabei wurde das Hauptmenü erstellt und mit den einzelnen Menüpunkten gefüllt. Klicks auf einzelne Menüpunkte wurden jedoch noch nicht behandelt. Unter anderem darum wird es heute gehen. Außerdem werden noch Ressourcendateien für Ganzzahlen und Animationen angelegt, der Header des NavigationDrawers angepasst, sowie eine neue Methode in der MainActivity implementiert.
Dieses Tutorial gibt es auch als Video
Kleine Ergänzungen in der MainActivity
Als erstes wird in der Methode „onCreate()“ der Datei mobile -> java -> de.smarthome_blogger.smarthome -> MainActivity.java der Titel gesetzt, der in der sogenannten ActionBar unter der Benachrichtigungsleiste des Smartphones angezeigt wird. Das machst du mit der folgenden Zeile:
setTitle("Smarthome");
Danach werden der Klasse zwei neue finale statische Variablen hinzugefügt. Dazu fügst du über der Methode „onCreate()“, aber unter der Variable „EXTRA_ROOMS“ die folgenden zwei Zeilen ein:
final static String EXTRA_TITLE = "EXTRA_TITLE"; final static String EXTRA_LOCATION = "EXTRA_LOCATION";
Zu den Variablen „drawerMenu“ und „drawerItemList“ unter dem Kommentar „//NavigationDrawer“ fügst du außerdem die folgenden 2 neuen Variablen hinzu:
DrawerLayout drawerLayout; FragmentTransaction fragmentTransaction;
DrawerLayout in „onCreate“ verwenden
In der Methode „onCreate“ befindet sich der folgende Code:
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.setDrawerListener(toggle); toggle.syncState();
Dieser wird nun mit diesem leicht abgewandelten Code ersetzt:
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawerLayout.setDrawerListener(toggle); toggle.syncState();
Die Methode „onNavigationItemSelected“ bearbeiten
Als nächstes muss die Methode „onNavigationItemSelected“ bearbeitet werden. Dazu werden die folgenden Zeilen entfernt:
// Handle navigaion view clicks here int id = item.getItemId(); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START);
Anschließend kommt an die Stelle der eben gelöschten Zeilen der folgende Code:
ArrayList menuItemArray = new ArrayList(); for(int i = 0; i < drawerMenu.size(); i++){ menuItemArray.add(drawerMenu.getItem(i)); drawerMenu.getItem(i).setChecked(false); } item.setChecked(true); drawerLayout.closeDrawers(); fragmentTransaction = getSupportFragmentManager().beginTransaction(); int position = menuItemArray.indexOf(item); Bundle bundle; try{ bundle = new Bundle(); bundle.putString(MainActivity.EXTRA_TITLE, drawerItemList.get(position).getName()); bundle.putString(MainActivity.EXTRA_LOCATION, drawerItemList.get(position).getLocation()); bundle.putString(MainActivity.EXTRA_ROOMS, roomData); setTitle(drawerItemList.get(position).getName()); drawerItemList.get(position).getFragment().setArguments(bundle); fragmentTransaction.replace(R.id.frame, drawerItemList.get(position).getFragment()); fragmentTransaction.commit(); } catch(IllegalStateException ise){ ise.printStackTrace(); }
Dieser Code behandelt Klicks auf das Menü des NavigationDrawers. Wird ein Menüpunkt angeklickt, so wird dieser als aktiv markiert und das entsprechende Fragment mit den entsprechenden Daten aufgerufen.
content_main.xml bearbeiten
Im vorherigen Code-Block wird in der vorletzten Zeile des try-Blocks die ID „R.id.frame“ verwendet. Diese muss nun dem entsprechenden Layout zugewiesen werden. Dazu öffnest du die Datei mobile -> res -> layout -> content_main.xml und fügst dort dem öffnenden RelativeLayout-Tag das folgende Attribut zu:
android:id="@+id/frame"
Bei Programmstart den ersten Menüpunkt auswählen
Damit der erste Menüpunkt bei Programmstart automatisch ausgewählt wird, wird der Methode „onCreate“ der Klasse MainActivity am Ende der folgende Code hinzugefügt:
//Das erste DrawerItem auswählen try{ onNavigationItemSelected(drawerMenu.getItem(0)); } catch(NullPointerException npe){ npe.printStackTrace(); }
Den Header des NavigationDrawers setzen
Damit der Header des NavigationDrawers mit eigenen Daten bestückt werden kann (als Text soll der Name des eingeloggten Nutzers angezeigt werden), müssen über der Methode „onCreate“ die folgenden Variable hinzugefügt werden:
//Header ImageView headerImage; TextView headerName; View headerLayout;
Anschließend wird am unteren Ende der Methode „onCreate“ der folgende Code eingefügt, um den Header dem NavigattionDrawer hinzuzufügen und ihn mit Daten zu füllen:
//Header laden headerLayout = navigationView.inflateHeaderView(R.layout.nav_header_main); headerName = (TextView) headerLayout.findViewById(R.id.username); headerName.setText(SaveData.getUsername(getApplicationContext()));
Als nächstes wird das Layout des Headers angepasst, da nur eine statt zwei Textzeilen benötigt wird. Dazu wird die Datei mobile -> res -> layout -> nav_header_main.xml geöffnet und der Code mit dem folgenden ersetzt:
<?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="@dimen/nav_header_height" android:background="@drawable/side_nav_bar" android:gravity="bottom" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:theme="@style/ThemeOverlay.AppCompat.Dark"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" android:src="@mipmap/ic_launcher" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" android:text="Android Studio" android:textAppearance="@style/TextAppearance.AppCompat.Body1" android:textColor="#FFFFFF" android:id="@+id/username"/> </LinearLayout>
Da der NavigationDrawer standardmäßig bereits einen Header enthält, muss dieser zuerst entfernt werden, damit er am Ende nicht zwei Header hat. Dazu wird die Datei mobile -> res -> layout -> activity_main.xml geöffnet und die folgende Zeile aus dem „android.support.design.widget.NavigationView“-Tag entfernt:
app:headerLayout="@layout/nav_header_main"
Die Methode „loadRooms“ erstellen
Im letzten Tutorial wurde beim Abfangen des Intents in der Methode „onCreate“ der Klasse MainActivity der folgende Code geschrieben:
//Intent abfangen Bundle extras = getIntent().getExtras(); if(extras != null && extras.containsKey(MainActivity.EXTRA_ROOMS)){ roomData = extras.getString(MainActivity.EXTRA_ROOMS); createRooms(roomData); } else{ //loadRooms(); }
Die Methode „loadRooms()“ ist auskommentiert, da sie noch nicht existiert. Du kannst die „//“ nun entfernen, da die Methode jetzt implementiert wird. Um dies zu tun, schreibst du den folgenden Code in den Klassen-Block der MainActivity:
/** * Lädt auf dem Server angelegte Räume und führt dann createRooms() aus */ public void loadRooms(){ Map<String, String> requestData = new HashMap<>(); requestData.put("action", "getrooms"); requestData.put("username", SaveData.getUsername(getApplicationContext())); requestData.put("password", SaveData.getPassword(getApplicationContext())); HTTPRequest.sendRequest(getApplicationContext(), requestData, SaveData.getServerIp(getApplicationContext()), new HTTPRequest.HTTPRequestCallback() { @Override public void onRequestResult(String result) { if(!result.equals("")){ roomData = result; createRooms(result); } else fehlermeldung("Serverfehler"); } @Override public void onError(String msg) { fehlermeldung(msg); } }); }
Ressourcendateien erstellen
Damit beispielsweise veschiedene Spaltenanzahlen von Layouts für veschiedene Bildschirmgrößen verwendet werden können, wird eine Ressourcendatei für ganze Zahlen angelegt, in der die entsprechenden Werte hinterlegt werden. Dazu klickst du mit rechts auf den Ordner (oder eine darin enthaltene Datei) unter dem Pfad mobile -> res -> values und wählst „New -> Values resource file“.
In dem Fenster das sich nun öffnet, gibst du als Namen der Datei „integers“ ein und klickst auf „OK“.
Nun öffnet sich die erstellte Datei und du ersetzt den Code mit dem folgenden:
<?xml version="1.0" encoding="utf-8"?> <resources> <integer name="grid_columns">2</integer> </resources>
Anschließend wird ein Verzeichnis für Animations-Ressourcendateien erstellt.
Dazu klickst du mit rechts auf den Ordner mobile -> res und wählst „New -> Directory“. Dort trägst du als Verzeichnisnamen „anim“ ein und klickst auf „OK“.
Danach klickst du mit rechts auf das eben angelegte Verzeichnis und wählst „New -> Animation resource file“. Jetzt gibst du als Dateinamen „recycler_animation“ ein und klickst auf „OK“. In der Datei, die sich nun öffnet, fügst du zwischen die set-Tags den folgenden Code ein:
android:interpolator="@android:anim/linear_interpolator"> <scale android:fromXScale="0.0" android:fromYScale="0.0" android:toXScale="1.0" android:toYScale="1.0" android:duration="250" android:fillBefore="false" /> <translate android:fromXDelta="50%" android:toXDelta="0%" android:fromYDelta="50%" android:toYDelta="0%" android:duration="250" />