Smarthome App #8: Raumsteuerung (2/2)


27.12.2016  |  Tutorial, Smarthome App

Bereits im letzten Tutorial wurde mit der Implementierung der Raumsteuerung der Smarthome App begonnen. Heute wird die Raumsteuerung fast abgeschlossen, indem die Verwaltung der Listenelemente implementiert wird. Zuvor wird außerdem noch ein Layout für ein Listenelement mit Schalter angelegt, zum Beispiel um Funksteckdosen zu steuern.

Layout-Datei für Schalter anlegen

Damit die Schalter für die Funksteckdosen in der App angezeigt werden können, muss zuerst eine Layout-Datei angelegt werden. Dazu klickst du den Ordner mobile -> res -> layout oder eine Datei darin mit der rechten Maustaste an und wählst „New -> Layout resource file“. Hier gibst du als Namen „switch_item“ und als „Root element“ „RelativeLayout“ ein und klickst auf „OK“. In der Datei, die sich nun geöffnet hat, ersetzt du den vorhandenen Code mit dem folgenden:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:padding="5dp">

    <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:weightSum="8"
                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"/>

                <Switch
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:id="@+id/switch_view"
                    android:layout_gravity="center"
                    android:layout_weight="3"/>

            </LinearLayout>

        </RelativeLayout>

    </android.support.v7.widget.CardView>

</RelativeLayout>

Raumelemente anzeigen

Damit alle Elemente eines Raumes in der Liste angezeigt werden, wird ein sogenannter Adapter benötigt. Dieser Adapter wird nun angelegt. Dazu öffnest die Datei mobile -> java -> de.smarthome_blogger.smarthome -> RoomFragment.java und fügst dort in den Block der Klasse die folgende Klasse ein:
public class RoomAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    final int VIEW_TYPE_SWITCH = 0;
    final int VIEW_TYPE_SENSOR = 1;
    final int VIEW_TYPE_HEATING = 2;
    final int VIEW_TYPE_SCENE = 3;

    int lastPosition = -1;

    @Override
    public int getItemCount(){
        return roomItems.size();
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int i){
        if(holder instanceof SwitchViewHolder){
            final RoomItem ri = roomItems.get(i);
            final SwitchViewHolder switchViewHolder = (SwitchViewHolder) holder;
            switchViewHolder.name.setText(ri.getName());
            switchViewHolder.icon.setImageResource(Icons.getDeviceIcon(ri.getDevice()));

            setState = true;
            switchViewHolder.switchView.setChecked(ri.getValue().equals("true"));
            setState = false;

            switchViewHolder.switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if(!setState){
                        setState = true;
                        switchViewHolder.switchView.setChecked(!switchViewHolder.switchView.isChecked());
                        setState = false;
                    }
                }
            });

            switchViewHolder.container.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    setState = true;
                    setModes(ri.getDevice(), !switchViewHolder.switchView.isChecked());
                    switchViewHolder.switchView.setChecked(!switchViewHolder.switchView.isChecked());
                    setState = false;
                }
            });

            setAnimation(((SwitchViewHolder) holder).container, i);
        }
        else if(holder instanceof SensorViewHolder){
            final RoomItem ri = roomItems.get(i);
            final SensorViewHolder sensorViewHolder = (SensorViewHolder) holder;
            sensorViewHolder.icon.setImageResource(Icons.getValueIcon(ri.getDevice()));
            sensorViewHolder.value.setText(ri.getValue());
            sensorViewHolder.name.setText(ri.getName());

            sensorViewHolder.container.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    showOverview(ri.getDevice());
                }
            });
        }
        else if(holder instanceof HeatingViewHolder){
            final RoomItem ri = roomItems.get(i);
            final HeatingViewHolder heatingViewHolder = (HeatingViewHolder) holder;
            heatingViewHolder.icon.setImageResource(Icons.getDeviceIcon(ri.getDevice()));
            heatingViewHolder.value.setText(ri.getValue());
            heatingViewHolder.name.setText(ri.getName());

            heatingViewHolder.container.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    openHeatingDialog();
                }
            });
        }
        else if(holder instanceof SceneViewHolder){
            final RoomItem ri = roomItems.get(i);
            final SceneViewHolder sceneViewHolder = (SceneViewHolder) holder;
            sceneViewHolder.icon.setImageResource(Icons.getSystemInfoIcon(ri.getName()));
            sceneViewHolder.name.setText(ri.getName());

            sceneViewHolder.container.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    openSceneMenu();
                }
            });
        }
    }

    public void setAnimation(View viewToAnimate, int position){
        if(position > lastPosition){
            Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.recycler_animation);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType){
        View itemView;
        switch(viewType){
            case VIEW_TYPE_SWITCH:
                itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.switch_item, viewGroup, false);
                return new SwitchViewHolder(itemView);
            case VIEW_TYPE_HEATING:
                itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.value_item, viewGroup, false);
                return new HeatingViewHolder(itemView);
            case VIEW_TYPE_SCENE:
                itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.value_item, viewGroup, false);
                return new SceneViewHolder(itemView);
            case VIEW_TYPE_SENSOR:
                itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.value_item, viewGroup, false);
                return new SensorViewHolder(itemView);
        }
        return null;
    }

    @Override
    public int getItemViewType(int position){
        if(roomItems.get(position).type.equals("switch")){
            return VIEW_TYPE_SWITCH;
        }
        else if(roomItems.get(position).type.equals("sensor")){
            return VIEW_TYPE_SENSOR;
        }
        else if(roomItems.get(position).type.equals("scene")){
            return VIEW_TYPE_SCENE;
        }
        else if(roomItems.get(position).type.equals("heating")){
            return VIEW_TYPE_HEATING;
        }
        return VIEW_TYPE_SENSOR;
    }

    public class SwitchViewHolder extends RecyclerView.ViewHolder{
        protected TextView name;
        protected ImageView icon;
        protected Switch switchView;
        protected View container;

        public SwitchViewHolder(View v){
            super(v);
            container = v.findViewById(R.id.container);
            name = (TextView) v.findViewById(R.id.name);
            icon = (ImageView) v.findViewById(R.id.icon);
            switchView = (Switch) v.findViewById(R.id.switch_view);
        }
    }

    public class SensorViewHolder extends RecyclerView.ViewHolder{
        protected TextView value, name;
        protected ImageView icon;
        protected View container;

        public SensorViewHolder(View v){
            super(v);
            container = v.findViewById(R.id.container);
            value = (TextView) v.findViewById(R.id.value);
            name = (TextView) v.findViewById(R.id.name);
            icon = (ImageView) v.findViewById(R.id.icon);
        }
    }

    public class HeatingViewHolder extends RecyclerView.ViewHolder{
        protected TextView value, name;
        protected ImageView icon;
        protected View container;

        public HeatingViewHolder(View v){
            super(v);
            container = v.findViewById(R.id.container);
            value = (TextView) v.findViewById(R.id.value);
            name = (TextView) v.findViewById(R.id.name);
            icon = (ImageView) v.findViewById(R.id.icon);
        }
    }

    public class SceneViewHolder extends RecyclerView.ViewHolder{
        protected TextView name;
        protected ImageView icon;
        protected View container;

        public SceneViewHolder(View v){
            super(v);
            container = v.findViewById(R.id.container);
            name = (TextView) v.findViewById(R.id.name);
            v.findViewById(R.id.value).setVisibility(View.GONE);
            icon = (ImageView) v.findViewById(R.id.icon);
        }
    }
}
Diese Klasse verwaltet die Liste der Elemente, die in einem Raum vorhanden ist. Außerdem werden Klicks auf einzelne Elemente registriert und die entsprechende Aktion ausgeführt. Der Adapter sorgt auch dafür, dass in der Liste auch Elemente mit verschiedenen Layouts vorhanden sein können und verwaltet diese.

Leere Methoden hinzufügen

Als letztes fügst du ein paar leere Methoden hinzu, die von der Klasse RoomAdapter verwendet werden. Sie sind Platzhalter für Aktionen, die ausgelöst werden, wenn ein die Schaltfläche zu einem bestimmte Element im Raum angetippt wird. Diese Methoden werden in einem späteren Tutorial implementiert.
/**
 * Schaltet das Ger&auml;t device auf den Zustand mode
 * @param device
 * @param mode
 */
public void setModes(String device, boolean mode){

}

/**
 * Zeigt Graphen f&uuml;r den Sensor sensor an
 * @param sensor
 */
public void showOverview(String sensor){}

/**
 * Heizungs-Men&uuml; &ouml;ffnen
 */
public void openHeatingDialog(){}

/**
 * Szenen-Men&uuml; &ouml;ffnen
 */
public void openSceneMenu(){}
Damit sind die Grundfunktionen Raumsteuerung fertig. Es müssen noch die leeren Methoden implementiert werden, was in einem späteren Tutorial geschieht. Außerdem wird sie in Zukunft noch um einige Funktionen erweitert werden. Wenn du Fragen oder Probleme hast, hinterlasse mir doch einen Kommentar.

Ü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!