Smarthome App #5: Einstellungs-Bildschirm (1/2)


01.11.2016  |  Tutorial, Smarthome App

Nachdem ich dir im letzten Tutorial gezeigt habe, wie du im Hauptmenü Klicks behandelst, um Menüpunkte auswählen zu können, wird heute der Menüpunkt "Einstellungen" genauer bearbeitet. Dazu wird unter anderem das entsprehende Fragment designed und implementiert.

Das Tutorial als Video ansehen!

Als erstes öffnest du die Datei mobile -> res -> layout -> fragment_settings.xml und erstellst dann eine neue Layout-Datei, indem du mit rechts auf den Layout-Ordner oder eine Datei darin klickst und dann "New -> Layout resource file" auswählst. Dieser Datei gibst du nun den Namen "value_item" und als "Root element" trägst du "FrameLayout" ein. Anschließend klickst du auf "OK". Wechsle dann wieder zu "fragment_settings.xml" und füge in den FrameLayout-Tag die folgenden zwei Zeilen ein:
android:id="@+id/frame"
android:background="@color/layoutBackground"
Danach ersetzt du diesen Codeblock
<!-- TODO: Update blank fragment layout-->
<TextView
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:text="Hello blank fragment" />
mit diesem Code:
<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/settings_list"></android.support.v7.widget.RecyclerView>

<include
    layout="@layout/loading_animation"
    android:visibility="gone"
    android:id="@+id/loading_animation" />
Als nächstes wird wieder eine neue Layout-Datei angelegt, indem du mit rechts auf eine Layout-Datei klickst und "New -> Layout resource file" wählst. Als Namen gibst du "loading_animation" und als "Root element" "RelativeLayout" ein. Dann klickst du auf "OK".
So wird die Datei
In der Leiste unten klickst du jetzt auf "Text", um zur Code-Ansicht zu gelangen und fügt zwischen dem öffnenden und dem schließenden RelativeLayout-Tag den folgenden Code ein:
<ProgressBar
	android:layout_width="150dp"
	android:layout_height="150dp"
	android:indeterminate="true"
	android:layout_centerInParent="true"/>
Die Dateien "fragment_settings.xml" und "loading_animation.xml" kannst du jetzt schließen, denn jetzt wird die Datei "value_item.xml" bearbeitet. Wähle sie in der Leiste oben aus und klicke dann in der unteren Leiste auf "Text", um zur Text-Ansicht zu gelangen. Füge dem FrameLayout-Tag das folgende Attribut hinzu:
android:padding="5dp"
Anschließend fügst du zwischen dem öffnenden und dem schließenden FrameLayout-Tag den folgenden Code ein:
<android.support.v7.widget.CardView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardElevation="@dimen/cardViewElevation"
    app:cardUseCompatPadding="true"
    android:id="@+id/container">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/recyclerItemHeight">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_centerInParent="true"
            android:layout_margin="3dp">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:id="@+id/icon"
                android:layout_gravity="center"
                android:layout_weight="2"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:id="@+id/name"
                android:layout_gravity="center"
                android:textColor="@color/textColorDark"
                android:gravity="center_vertical|center_horizontal"
                android:layout_weight="3"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:id="@+id/value"
                android:layout_gravity="center"
                android:textColor="@color/textColorDark"
                android:gravity="center_vertical|center_horizontal"
                android:layout_weight="3"/>

        </LinearLayout>

    </RelativeLayout>

</android.support.v7.widget.CardView>
Nun öffnest du die Datei mobile -> java -> de.smarthome_blogger.smarthome -> SettingsFragment. Dort deklarierst du über der Methode "public SettingsFragment()" die folgenden neuen Variablen:
//RecyclerView
RecyclerView.Adapter settingsAdapter;
GridLayoutManager glm;
ArrayList<SettingItem> settingItems;
RecyclerView settingArray;

View settingsView;
Am unteren Ende der Klasse, aber über der letzten schließenden Klammer erstellst du nun eine neue Klasse "SettingItem", die die Informationen eines Werte-Elements beinhaltet:
class SettingItem{
    private String name, type;
    private String value;
    private View.OnClickListener ocl;

    public SettingItem(String name, String type, String value, View.OnClickListener ocl){
        this.name = name;
        this.type = type;
        this.value = value;
        this.ocl = ocl;
    }

    /**
     * Gibt den Namen zur&uuml;ck
     * @return
     */
    public String getName(){
        return name;
    }

    /**
     * Gibt den Typ zur&uuml;ck
     * @return
     */
    public String getType(){
        return type;
    }

    /**
     * Gibt den Wert zur&uuml;ck
     * @return
     */
    public String getValue(){
        return value;
    }

    /**
     * Gibt den OnClickListener zur&uuml;ck
     * @return
     */
    public View.OnClickListener getOnClickListener(){
        return ocl;
    }
}
Danach ersetzt du in der Methode "public View onCreateView()" die Zeilen, damit die oben deklarierten Variablen nun Instanziiert werden und die RecyclerView aus der Layout-Datei referenziert und mit Daten gefüllt wird:
//Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_settings, container, false);
mit diesem Code:
// Inflate the layout for this fragment
settingsView = inflater.inflate(R.layout.fragment_settings, container, false);

settingArray = (RecyclerView) settingsView.findViewById(R.id.settings_list);
settingArray.setHasFixedSize(true);
glm = new GridLayoutManager(getContext(), getResources().getInteger(R.integer.grid_columns));
glm.setOrientation(GridLayoutManager.VERTICAL);
settingArray.setLayoutManager(glm);

settingItems = new ArrayList<>();

loadSystemInfo();

return settingsView;
Als nächstes wird die Methode "loadSystemInfo()" implementiert, die die Server-Informationen aus dem Tutorial Systemdaten des Raspberry Pi abrufen abfragt und die Liste damit füllt. Schreibe dazu den folgenden Code in die Klasse SettingsFragment:
/**
 * L&auml;dt die Server-Infos vom Server herunter und zeigt sie an
 */
public void loadSystemInfo(){
    settingsView.findViewById(R.id.loading_animation).setVisibility(View.VISIBLE);

    final Map<String, String> requestData = new HashMap<>();
    requestData.put("action", "getsysteminfo");
    requestData.put("username", SaveData.getUsername(getContext()));
    requestData.put("password", SaveData.getPassword(getContext()));

    HTTPRequest.sendRequest(getContext(), requestData, SaveData.getServerIp(getContext()), new HTTPRequest.HTTPRequestCallback() {
        @Override
        public void onRequestResult(String result) {
            settingsView.findViewById(R.id.loading_animation).setVisibility(View.GONE);

            //Ergebnis is Log schreiben
            Log.i("GetSystemInfo-Result", result);

            if(result.equals("wrongdata")){
                fehlermeldung("Anmeldung nicht m&ouml;glich!\nBitte logge dich erneut ein.");
            }
            else if(result.equals("unknownuser")){
                fehlermeldung("Dieser Nutzer existiert nicht!\nBitte logge dich erneut ein.");
            }
            else{
                try{
                    JSONObject jsonObj = null;
                    try{
                        jsonObj = new JSONObject(result);
                    }
                    catch(JSONException e){
                        e.printStackTrace();
                    }

                    JSONArray systemInfo = jsonObj.getJSONArray("systeminfo");

                    for(int i = 0; i < systemInfo.length(); i++){
                        JSONObject o = systemInfo.getJSONObject(i);

                        settingItems.add(new SettingItem(o.getString("name"), o.getString("type"), o.getString("value"), null));
                    }

                    //Statische Men&uuml;punkte
                    settingItems.add(new SettingItem("Szenen", "scenes", "", new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            //Szenen-Verwaltung &ouml;ffnen
                            fehlermeldung("Szenen-Verwaltung");
                        }
                    }));

                    settingItems.add(new SettingItem("Nutzer", "user", "", new View.OnClickListener(){
                        @Override
                        public void onClick(View v){
                            //Nutzer-Verwaltung &ouml;ffnen
                            fehlermeldung("Nutzer-Verwaltung");
                        }
                    }));

                    settingItems.add(new SettingItem("Automation", "automation", "", new View.OnClickListener(){
                        @Override
                        public void onClick(View v){
                            //Automations-Verwaltung
                            fehlermeldung("Automations-Verwaltung");
                        }
                    }));

                    //Adapter setzen
                    settingsAdapter = new SettingsAdapter();
                    settingArray.setAdapter(settingsAdapter);
                    settingsAdapter.notifyDataSetChanged();
                }
                catch(Exception e){
                    fehlermeldung("Fehler beim Laden der Systeminformationen");
                }
            }
        }

        @Override
        public void onError(String msg) {
            settingsView.findViewById(R.id.loading_animation).setVisibility(View.GONE);
            fehlermeldung(msg);
        }
    });

}
Als letztes wird noch die Methode "fehlermeldung()" implementiert, die übergebene Texte ausgibt:
/**
 * Zeigt &uuml;bergebene Fehlermeldung an
 * @param msg
 */
public void fehlermeldung(String msg){
    Snackbar.make(settingsView.findViewById(R.id.frame), msg, Snackbar.LENGTH_SHORT).show();
}
Im nächsten Teil des Tutorials wird unter anderem ein sogenannter Adapter implementiert, der die Liste mit den entsprechenden Daten füllt. Wenn du Fragen oder Probleme hast, kannst du mir gerne einen Kommentar hinterlassen.

Über den Autor


Sascha Huber

Hallo, ich bin Sascha, der Gründer von Smarthome Blogger.

Mit einer Leidenschaft für Technologie und einem Hintergrund als Software Engineer habe ich 2016 Smarthome Blogger gegründet. Mein Ziel war es schon immer, innovative Lösungen zu entdecken, die unser Leben einfacher und intelligenter gestalten können. In meinem beruflichen Leben arbeite ich täglich mit Software und Technik, aber auch in meiner Freizeit bin ich stets auf der Suche nach neuen technischen Spielereien und Möglichkeiten, mein Zuhause zu automatisieren und zu verbessern.

Auf Smarthome Blogger teile ich mein Wissen, meine Erfahrungen und meine Begeisterung für alles rund um das Thema Smarthome.



Dieser Beitrag hat dir gefallen?

Dann abonniere doch unseren Newsletter!