Adapter Class mit Image Buttons - wie ImageResource speichern?

  • Antworten:12
  • Bentwortet
Christian Hackbusch
  • Forum-Beiträge: 14

05.06.2017, 23:44:51 via Website

Hallo zusammen... (in voller Hoffnung (whew))

wir müssen in der Schule gerade unsere erste Android App entwickeln. Ist leider alles nicht so einfach. Ganz allgemein zur Idee: Es gibt eine Kategorie (z.B. Inseln) die eine Adapter Klasse enthält. Wenn die Insel-Kategorie ausgewählt ist, kann man inzwischen zwischen unterschiedlichen Inseln hin und her swipen. Das Layout zum swipen enthält einen TextView der mitzählt bei der wie vielten Insel wir gerade sind (z.B. 2/10). Darunter befindet sich dann ein Image welches in der Adapter Class instanziiert wird und darunter ist mein großes Problem. Ich hab einen ImageButton eingebaut. Der soll am Ende dazu dienen, dass man eine Insel als Favorit markieren kann. Aktuell funktioniert das so, dass die ImageResource durch klicken geändert wird, aber nirgendwo abgespeichert ist (wirklich nur provisorisch...).

Ziel ist auf jeden Fall, dass wenn ich mich erneut einlogge, die ImageButton noch so aussehen wie zuvor. Leider kenn ich mich bisher nicht gut damit aus. Als Neuling hab ich mich mit SQLite und SharedPreferences versucht, in beiden Fällen jedoch erfolglos.

Ich füge einfach mal den wichtigsten Code ein, damit ihr einen Eindruck vom Aufbau bekommt. Vielleicht kennt sich hier jemand aus und kann mal ein Auge darauf werfen. Wäre wirklich dankbar über jeden Vorschlag... So langsam bin ich nämlich am verzweifeln :'(

Layout für die Inseln

<RelativeLayout xmlns:android="...link entfernt weil neues Mitglied..."
    xmlns:app="...link entfernt weil neues Mitglied..."
    xmlns:tools="...link entfernt weil neues Mitglied..."
    android:id="@+id/activity_suggestion"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hska.app.activities.SuggestionActivity" >

    <android.support.v7.widget.Toolbar
        android:id="@+id/suggestion_toolbar"
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:background="@color/colorTextHint"
        android:elevation="4dp"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

    <TextView
        android:id="@+id/category_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="85dp"
        android:text="Beautiful Islands"
        android:textColor="@android:color/black"
        android:textSize="28sp"
        android:gravity="center"
        android:textStyle="bold"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />

    <android.support.v4.view.ViewPager
        android:id="@+id/image_swipe"
        android:layout_width="match_parent"
        android:layout_height="590dp"
        android:layout_marginTop="130dp" />

</RelativeLayout>

Layout zum Adapter (das was man wischen kann)

<LinearLayout xmlns:android="...link entfernt weil neues Mitglied..."
    xmlns:app="...link entfernt weil neues Mitglied..."
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/image_count"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Here we count..."
        android:textColor="@android:color/black"
        android:textSize="16sp" />

    <ImageView
        android:id="@+id/swipe_image"
        android:layout_width="match_parent"
        android:layout_height="365dp"
        android:layout_marginBottom="20dp"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"/>

    <ImageButton
        android:id="@+id/favourite_button"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_gravity="center"
        android:background="@android:color/transparent"
        android:onClick="onClickFav"
        android:scaleType="fitCenter"
        android:src="@drawable/heart" />

</LinearLayout>

Insel Klasse

public class SuggestionActivity extends AppCompatActivity {

ViewPager viewPager;
SwipeAdapter adapter;

private boolean nofav = true;

private final AppCompatActivity activity = SuggestionActivity.this;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_suggestion);

    viewPager = (ViewPager) findViewById(R.id.image_swipe);
    adapter = new SwipeAdapter(this);
    viewPager.setAdapter(adapter);

    Toolbar sToolbar = (Toolbar) findViewById(R.id.suggestion_toolbar);
    setSupportActionBar(sToolbar);
}

public void onClickFav(View v) {
    ImageButton favouriteButton = (ImageButton) v;

    Boolean isFav = favouriteButton.getTag() == null ? Boolean.FALSE : (Boolean) favouriteButton.getTag();

    favouriteButton.setImageResource(isFav ? R.drawable.heart : R.drawable.heart_red);

    if (isFav) {
        Toast.makeText(SuggestionActivity.this, "No favourite anymore...",
                Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(SuggestionActivity.this, "Woah, new favourite!",
                Toast.LENGTH_SHORT).show();
    }

    favouriteButton.setTag(!isFav);
}
}

...und zuletzt noch die Adapter Klasse

public class SwipeAdapter extends PagerAdapter  {

private int[] image_resources = {
        R.drawable.island1,
        R.drawable.island2,
        R.drawable.island3,
        R.drawable.island4,
        R.drawable.island5,
        R.drawable.island6,
        R.drawable.island7,
        R.drawable.island8,
        R.drawable.island9,
        R.drawable.island10
};

private Context context;
private LayoutInflater layoutInflater;

public SwipeAdapter(Context context) {
    this.context = context;
}

@Override
public int getCount() {
    return image_resources.length;
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return (view == (LinearLayout) object);
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View item_view = layoutInflater.inflate(R.layout.swipe_layout,container,false);
    ImageView imageView = (ImageView) item_view.findViewById(R.id.swipe_image);
    TextView textView = (TextView) item_view.findViewById(R.id.image_count);

    imageView.setImageResource(image_resources[position]);
    textView.setText("["+(position+1)+"/10]");

    container.addView(item_view);

    return item_view;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((LinearLayout) object);
}
} 

...falls wer bis hier unten gelesen hat, allein Danke dafür! (cool)

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

06.06.2017, 08:29:19 via Website

Hallo Christian,
so ganz habe ich noch nicht verstanden, was du eigentlich umsetzen willst...

Mal von Anfang:

Du hast eine Activity, welche ein ViewPager besitzt. In diesem hast du mehrere Fragments ( mehrere Instanzen einer InselFragment Klasse) zum swipen.
Dieses Fragment weiß an welcher Postition es steht und zeigt dann etwas in der TextView und dem Image an.

Was genau soll passieren, wenn man nun auf den ImageButton klickt?
Was soll das Ziel dahinter sein?

— geändert am 06.06.2017, 08:29:29

LG Pascal //It's not a bug, it's a feature. :) ;)

Christian Hackbusch

Antworten
Christian Hackbusch
  • Forum-Beiträge: 14

06.06.2017, 10:33:13 via Website

Hey Pascal,

Genau. Die Activity setzt sich aus einem TextView (feste Überschrift "Inseln", wischt nicht mit) und dem ViewPager zusammen. Der ViewPager besteht aus TextView, Image und dem ImageButton unter dem Image. TextView und Image funktionieren so wie sie es sollen.

Wenn man auf den ImageButton (zum Favorit markieren) klickt, ändert sich aktuell das Bild (favouriteButton.setImageResource). Um eine bessere Vorstellung zu bekommen: standardmäßig ist der ImageButton ein graues Herz (heart), wenn man drauf klickt ein rotes Herz (heart_red). Wenn man noch einmal darauf klickt, ist das Herz wieder grau. Dementsprechend wird auch noch eine kurze Textmeldung ausgegeben, die kann man aber erstmal vernachlässigen.

Ziel ist also, dass der User die Inseln mit einem roten Herz markieren kann, die ihm besonders gefallen. Und diese Markierungen sollen auch nachdem man die App neu startet noch vorhanden sein. Ganz am Ende sollen dann alle die als Favorit markiert wurden über das Menu gefiltert werden (das ist aber nochmal eine andere Geschichte, die hier nicht das Thema sein soll).

Hoffe man versteht es jetzt besser... Vielleicht ist das mit einem ImageButton auch umständlich?

— geändert am 06.06.2017, 10:35:25

Antworten
swa00
  • Forum-Beiträge: 3.704

06.06.2017, 10:43:27 via Website

Hallo Christian,

Einen ImageButton kannst du jederzeit mit einem neuen Image versehen ( graues /rotes Herz)
Dazu baust du dir z.B. einen Boolean Flag und wechselst diesen beim ClickListener.

Abspeichern musst du natürlich den letzten Status : entweder in den Shares, oder in einer DB.
Und da scheinst du irgendwas fasch gemacht zu haben , denn beides würde funktionieren .

Und wenn das Fragment visible wird ( erkennst du im Pager) dann setzt du dir die entsprechenden Images
auf deine Imagebuttons.

— geändert am 06.06.2017, 10:47:04

Liebe Grüße - Stefan
[ App - Entwicklung ]

Christian Hackbusch

Antworten
Christian Hackbusch
  • Forum-Beiträge: 14

06.06.2017, 10:56:30 via Website

Hi Stefan,

die ImageResource müsste ja dann in der Adapter Klasse in folgender Methode public Object instantiateItem(ViewGroup container, int position) { } entsprechend dem Flag geladen werden oder?

Ich hatte es mal mit SharedPreferences und einer DB versucht, leider ohne Erfolg. Hast du vielleicht eine gute Anleitung zu der du mir den Link da lassen kannst? Dann würde ich es nochmal versuchen...

Und nochmal zum Verständnis, so sieht das ganze aktuell aus, nur dass die ImageButtons eben nicht abgespeichert werden.

— geändert am 06.06.2017, 22:41:56

Antworten
swa00
  • Forum-Beiträge: 3.704

06.06.2017, 11:02:18 via Website

Hallo Christian,

natürlich kannst du das in Object instantiateItem(ViewGroup container, int position) { } zur initalisierung setzen,
Die verwendest du aber nur einmal im Pager ( bei getItem) oder wenn die Seite nochmal vom Pager benötigt wird.
Du musst aber dynamisch bleiben und auch während der Laufzeit auf Änderungen reagieren können.
Also baue dir für dein Fragment eine Funktion / getter / setter und da setzt du die Images.

Shared ist einfach
https://www.tutorialspoint.com/android/android_shared_preferences.htm

DB auch
http://www.vogella.com/tutorials/AndroidSQLite/article.html

— geändert am 06.06.2017, 11:03:14

Liebe Grüße - Stefan
[ App - Entwicklung ]

Christian Hackbusch

Antworten
Christian Hackbusch
  • Forum-Beiträge: 14

06.06.2017, 11:11:24 via Website

Ich bedanke mich schonmal. Werde mich (nach einem motivierenden Frühstück) mal daran versuchen und mich dann melden! (cool)

Antworten
Christian Hackbusch
  • Forum-Beiträge: 14

06.06.2017, 13:23:44 via Website

Hab jetzt mal eben versucht, die StoredPreferences anzuwenden. Das Problem ist, dass der ImageButton teilweise in dem Main View erwartet wird, er aber eben im View Pager sitzt. Deshalb bekomme ich eine NullPointerException sofern ich das richtig verstehe...

User uploaded photo

Noch zu meinem Versuch der Umsetzung von SharedPreferences:

Insel Klasse (main activity):

public class SuggestionActivity extends AppCompatActivity {

    ViewPager viewPager;
    SwipeAdapter adapter;
    ImageButton favouriteButton;

    // variables for shared preferences
    public static final String MyPREFERENCES = "MyPrefs";
    public static final String Favorite = "favoriteKey";

    SharedPreferences sharedpreferences;

    private final AppCompatActivity activity = SuggestionActivity.this;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_suggestion);

        favouriteButton = (ImageButton) findViewById(R.id.favourite_button);
        sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);

        viewPager = (ViewPager) findViewById(R.id.image_swipe);
        adapter = new SwipeAdapter(this);
        viewPager.setAdapter(adapter);

        Toolbar sToolbar = (Toolbar) findViewById(R.id.suggestion_toolbar);
        setSupportActionBar(sToolbar);
    };

     /*
        Method for click actions on the favorite button
        @heart grey heart symbolizes no favorite (flag 0)
        @heart_red red heart symbolizes marked as favorite (flag 1)
    */
    public void onClickFav(View v) {
        ImageButton favouriteButton = (ImageButton) v;

        // getTag of current image button
        String isFav = favouriteButton.getTag() == null ? "0" : "1";

        // set image resource dependent on what flag is set
        favouriteButton.setImageResource(isFav == "1" ? R.drawable.heart : R.drawable.heart_red);

        // do some magic text dependent on what flag is set
        if (isFav == "1") {
            Toast.makeText(SuggestionActivity.this, "No favourite anymore...",
                    Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(SuggestionActivity.this, "Woah, new favourite!",
                    Toast.LENGTH_SHORT).show();
        }

        // switch tag to opposite
        favouriteButton.setTag(isFav == "0" ? "1" : "0");

        // store tag for preferences
        String f = favouriteButton.getTag().toString();

        SharedPreferences.Editor editor = sharedpreferences.edit();

        editor.putString(Favorite, f);
        editor.commit();
    }

}

Swipe Adapter

     /*
        Instantiate an single adapter item
        Set image resources and text about current position
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View item_view = layoutInflater.inflate(R.layout.swipe_layout,container,false);
        ImageView imageView = (ImageView) item_view.findViewById(R.id.swipe_image);
        TextView textView = (TextView) item_view.findViewById(R.id.image_count);
        ImageButton imageButton = (ImageButton) item_view.findViewById(R.id.favourite_button);

        imageView.setImageResource(image_resources[position]);
        textView.setText("["+(position+1)+"/10]");

        imageButton.setImageResource(imageButton.getTag().toString() == "1" ? R.drawable.heart : R.drawable.heart_red);

        container.addView(item_view);

        return item_view;
    }

Hat jemand eine Idee wie das Problem mit der Exception gelöst werden kann? Das hier geht glaube ich in die selbe Richtung:

Darf noch keine Links... stackoverflow.com/questions/28193552/null-pointer-exception-on-setonclicklistener

Antworten
swa00
  • Forum-Beiträge: 3.704

06.06.2017, 13:49:18 via Website

ja, weil dein Objekt, aus welchem du toString() bilden willst, null ist.

Und so ganz nebenbei sich nicht in dem von dir geposteten Source befindet.
Oder sagen wir mal besser - was ist zeile 71 bei dir ?

So können wir auch nur rätseln :-)
Und ein wenig leichter könntest du es uns auch machen

— geändert am 06.06.2017, 13:50:53

Liebe Grüße - Stefan
[ App - Entwicklung ]

Antworten
Christian Hackbusch
  • Forum-Beiträge: 14

06.06.2017, 14:28:43 via Website

Oh na klar, hatte ganz vergessen, dass die Tags am Anfang erstmal null sind (lightbulb)

Zeile 71 war:

imageButton.setImageResource(imageButton.getTag().toString() == "1" ? R.drawable.heart : R.drawable.heart_red);

Hab die Zeile in der instantiateItem Methode inzwischen hierdurch ersetzt:

if (imageButton.getTag() == null) {
   imageButton.setImageResource(R.drawable.heart);
} else if (imageButton.getTag() == "0") {
   imageButton.setImageResource(R.drawable.heart);
} else if (imageButton.getTag() == "1") {
   imageButton.setImageResource(R.drawable.heart);
}

...und dementsprechend auch keine Fehlermeldung mehr.

onClickFav() in der main acitivity habe ich auch noch abgeändert damit alle Fälle abgedeckt sind:

     /*
        Method for click actions on the favorite button
        @heart grey heart symbolizes no favorite (flag 0)
        @heart_red red heart symbolizes marked as favorite (flag 1)
    */
    public void onClickFav(View v) {
        ImageButton favouriteButton = (ImageButton) v;

        // getTag of current image button
        // set image resource dependent on what flag is set
        if (favouriteButton.getTag() == null) {
            favouriteButton.setImageResource(R.drawable.heart_red);
        } else if (favouriteButton.getTag() == "0") {
            favouriteButton.setImageResource(R.drawable.heart_red);
        } else if (favouriteButton.getTag() == "1") {
            favouriteButton.setImageResource(R.drawable.heart);
        }

        // do some magic text dependent on what flag is set
        if (favouriteButton.getTag() == "1") {
            Toast.makeText(SuggestionActivity.this, "No favourite anymore...",
                    Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(SuggestionActivity.this, "Woah, new favourite!",
                    Toast.LENGTH_SHORT).show();
        }

        // switch tag to opposite, null becomes also 1
        favouriteButton.setTag(favouriteButton.getTag() == "1" ? "0" : "1");

        // store tag for preferences
        String f = favouriteButton.getTag().toString();

        SharedPreferences.Editor editor = sharedpreferences.edit();

        editor.putString(Favorite, f);
        editor.commit();
    }

Die ImageResource wird jedoch nicht abgespeichert. Scheint also als hab ich irgendwo einen Fehler gemacht... :?

Antworten
Christian Hackbusch
  • Forum-Beiträge: 14

06.06.2017, 21:27:36 via Website

UPDATE: Bisher war es ja auch so, dass der key für den der Wert abgespeichert wurde, bei jedem item der selbe war. Deshalb hab ich jetzt versucht für jedes item einen unique key festzulegen (zusammengesetzt aus fav und dem Text aus dem ImageView). Sieht dann so aus:

public void onClickFav(View v) {
        ImageButton favouriteButton = (ImageButton) findViewById(R.id.favourite_button);
        TextView textview = (TextView) findViewById(R.id.image_count);

        String text = textview.getText().toString();

        SharedPreferences prefs = getSharedPreferences("favInfo", MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();

        // get the unique key consisting of fav and the count text
        String key = "fav" + text;

        // get value stored with that key, default: if no value exists take 0
        String electedValue = prefs.getString(key, "0");

        // check if value of favorite key is 0, 
        // set image resource dependent on what value is stored behind the key
        if (electedValue == "0") {
            favouriteButton.setImageResource(R.drawable.heart_red);
        } else {
            favouriteButton.setImageResource(R.drawable.heart);
        }

        // do some magic text dependent on what value is set
        if (electedValue == "1") {
            Toast.makeText(SuggestionActivity.this, "No favourite anymore...",
                    Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(SuggestionActivity.this, "Woah, new favourite!",
                    Toast.LENGTH_SHORT).show();
        }

        String isFav;

        // switch value to opposite
        if (electedValue == "0") {
            isFav = "1";
        } else {
            isFav = "0";
        }

        // store shared preferences
        editor.putString(key, isFav);
        editor.commit();
    }

@Override
    public Object instantiateItem(ViewGroup container, int position) {
        layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View item_view = layoutInflater.inflate(R.layout.swipe_layout,container,false);
        ImageView imageView = (ImageView) item_view.findViewById(R.id.swipe_image);
        TextView textView = (TextView) item_view.findViewById(R.id.image_count);
        ImageButton imageButton = (ImageButton) item_view.findViewById(R.id.favourite_button);

        imageView.setImageResource(image_resources[position]);
        textView.setText("["+(position+1)+"/10]");

        SharedPreferences prefs = context.getSharedPreferences("favInfo", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();

        // get the unique key out of fav and the count text
        String text = "["+(position+1)+"/10]";
        String key = "fav" + text;

        String electedValue = prefs.getString(key, "0");

        // check if value of favorite key is 0
        // set image resource dependent on what value is set
        if (electedValue == "0") {
            imageButton.setImageResource(R.drawable.heart_red);
        } else {
            imageButton.setImageResource(R.drawable.heart);
        }

        container.addView(item_view);

        return item_view;
    }

Jetzt kommt die ganze Zeit aber nur "Woah, new Favorite" aber am Button selbst ändert sich nichts... Nur nach Neustart haben sich manche Buttons geändert... Jemand eine Idee woran das liegen kann?

Danke für die Hilfe.... (*)

— geändert am 06.06.2017, 22:00:11

Antworten
swa00
  • Forum-Beiträge: 3.704

06.06.2017, 22:04:41 via Website

Hallo Christian,

ich muss gestehen , ich hatte mal exakt die gleichen Problem mit den Shares wie du :-)
Seit dem Punkt habe ich dann völlig entnervt alles auf DB umgestellt - ich war es leid

Und nu ist bei mir Ruhe im Karton

Liebe Grüße - Stefan
[ App - Entwicklung ]

Christian Hackbusch

Antworten
Christian Hackbusch
  • Forum-Beiträge: 14

06.06.2017, 22:53:29 via Website

Verstehe, trotzdem mal danke für die Hilfe! ;) Ich bin ganz nah dran. Die Daten werden wirklich abgespeichert. Hab die String-Vergleiche mit == durch .equals ersetzt. Jetzt ist es aber teilweise so, dass wenn ich beim 10ten item auf den ImageButton drücke, sich der vom 9ten Image verändert :?

TextView textview = (TextView) findViewById(R.id.image_count);
String text = textview.getText().toString();

Bei dem Teil hier wird teilweise nicht das abgespeichert was gerade zu sehen ist (wieso auch immer). Habe es gerade getestet. In text wird dann der Text vom item davor oder danach genommen, aber widerum auch nicht in allen Fällen.

Sprich: die einzelnen items (Inseln) können nicht exakt bestimmt werden mit einer unique id. Vielleicht hat ja noch wer anders einen Einfall wie man die eindeutig identifizieren kann... (silly)

Antworten