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 "loading_animation.xml" definiert. So wird die Datei "loading_animation.xml" definiert.
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ück
     * @return
     */
    public String getName(){
        return name;
    }

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

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

    /**
     * Gibt den OnClickListener zurü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ä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ö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üpunkte
                    settingItems.add(new SettingItem("Szenen", "scenes", "", new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            //Szenen-Verwaltung öffnen
                            fehlermeldung("Szenen-Verwaltung");
                        }
                    }));

                    settingItems.add(new SettingItem("Nutzer", "user", "", new View.OnClickListener(){
                        @Override
                        public void onClick(View v){
                            //Nutzer-Verwaltung ö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 ü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.


Dieser Beitrag hat dir gefallen?

Dann abonniere doch unseren Newsletter!