# ViewFlipper



## jf (11. Apr 2012)

Hallo, ich komme langam voran - die nächste Hürde, welche zu nehmen ist, ist der ViewFlipper.
Hier habe ich noch ein Verständnisproblem der genauen Arbeitsweise des Flippers. Folgender Code kann erst einmal nur eine Ebene tief flippen:


```
public class MenuView extends ViewFlipper {
	
	private int id = 1000;

	public MenuView(final Context context, Menu menu) {
		super(context);

		final ListViewEx<MenuEntry> list = new ListViewEx<MenuEntry>(context);
		list.addItems( menu.getMainPage().getEntries() );
		
		list.setOnItemClickListener(new OnItemClickListener() {
			// When clicked, show a toast with the TextView text
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				MenuEntry item = (MenuEntry)list.getItemAtPosition(position);
				
				int viewID = MenuView.this.id++;
				final ListViewEx<MenuEntry> nextView = new ListViewEx<MenuEntry>(context);
				nextView.addItems( item.getSubmenu().getEntries() );
				nextView.setId(viewID);
				
				MenuView.this.addView(nextView);
				MenuView.this.setNextFocusDownId(viewID);
				MenuView.this.showNext();
				
	    		Toast.makeText(context, item.toString(), Toast.LENGTH_SHORT).show();
	    	}
		});
		
		this.addView(list);
	}


    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        super.onInterceptTouchEvent(event);
        Log.e("SWIPED", "onInterceptTouchEvent : " + event.getAction());
        if(event.getAction() == 2) {
        	//this.removeView(event.getSource());
        	this.showPrevious();
        }
        return false;
    }
}
```

Ich erstelle im OnItemClickListener die nächste View in Abhängigkeit der jeweiligen Nutzereingabe.
Ich gebe der View eine eindeutige ID, welche für den nächsten Schritt automatisch hochgezählt wird.
Die View wird dem Flipper hinzugefügt, die vergebene ID dem Flipper als Identifizierung der nächsten View mitgeteilt und anschließend mit showNext() die View letztentlich gewechselt.

Kann der ViewFlipper jeweils nur zwischen zwei Views wechseln?

Wenn ich eine Ebene zurück gehe, dann muss ich die aktuelle View natürlich wieder entfernen.
Wie kann ich das realisieren? - Bekomme ich irgendwie über das MotionEvent die View über welche der Finger bewegt wurde?

Außerdem ist event.getAction() ungünstig, um den Swipe zu detektieren. - Aber eine Methode wie "getDirection()" kennt das MotionEvent nicht. Aus der Doku bin ich auch noch nicht schlau geworden... Google könnte mal ein Bespiel für die am häufigsten verwendeten Gesten mit aufnehmen.


----------



## jf (12. Apr 2012)

Ich krieg die Kriese: Eclipse erkannte gerade eben den Emulator nicht mehr, obwohl dieser gestartet war!
Habe den AVD daraufhin gelöscht und neu angelegt - jetzt startet er noch nicht einmal mehr... ;(

Dann habe ich zwecks des Gesten-Problems mal die Klasse von hier ausprobiert: Funktion leider Fehlanzeige!
=> Die Geste wird nicht erkannt, dafür funktioniert das Anklicken eines Listeneintrages nicht mehr zuverlässig: Prima!

Dann sind die ListView-Einträge auf dem Text-Gerät (Motorola Defy) so winzig, dass man sie kaum lesen, geschweige denn gescheit antippen kann. - Eine bitter nötige Einstellungsmöglichkeit hierfür, konnt eich im gesamten Telefon leider nicht finden! :autsch:

Dann gibt es bei dem ViewFlipper auch noch ein Problem mit dem OnItemClickListener:
Dieser bleibt aktiv, auch wenn die dazugehörige View bereits ausgeblendet ist - was soll der Mist?

=> Mir scheint, hier wurde an allen Ecken und Enden mit heißer Nadel gestrickt!


----------



## jf (12. Apr 2012)

Ok, das Problem mit dem OnItemClickListener war mein Fehler!
Hatte dummerweise zu jeder Seite das selbe Listener-Objekt hinzugefügt... 

Nach wie vor suche ich aber nach einer Klasse, welche mir die Basis-Gesten liefert:

swipe in die 4 Himmelsrichtungen (idealerweise mit Information zur Anzahl der verwendeten Finger)
pinch für zoom_in und zoom_out
double tab

und natürlich das Schriftgrößen-Problem... ideal wäre eine Schrift wie hier.
=> Weiß hierzu evtl. noch jemand einen Rat?


----------



## schlingel (13. Apr 2012)

Also die 3 Punkte die du da haben möchtest, musst du dir selber schreiben.

Ein ViewFlipper kann nur 2D-Gesten. Standard ist nach links oder rechts wischen. Pinch für Zoom-In und Zoom-Out musst du dir auch selber schreiben. Bei Android 2.1 ist da noch nichts dabei, ich glaub erst ab Honeycomb. (Hier gibt's Quellen dazu.)

Double Tab ditto. Wobei ich davon abraten möchte, weil das absolut außerirdisch ist auf mobilen Plattformen. Auf Android gibt's den Long-Click oder den Click. Doppelklick macht auf einem Smartphone einfach wenig Sinn. Behilf dir da lieber mit Quick-Actions.

Was genau möchtest du den zoomen? Controls oder nur ein Bild? Controls ist generell schwierig, wenn du da eine Lösung findest wäre ich auch sehr daran interessiert.

Punkto deines ViewFlipper-Problems: Vielleicht hast du mit dem ViewPager aus dem Support Package mehr Erfolg. In dem Fall hast du wieder einen Adapter der die Seiten bzw. Views für die Anzeige enthält - ähnlich dem ListView-Adapter. Dort könntest du bei dem Flip-Event die Liste manipulieren so dass sie danach aussieht wie du es brauchst.

Schrifttyp kannst du mit dem typeface-Attribut ändern.


----------



## jf (13. Apr 2012)

Hallo Schlingel, schön, dass sich wenigstens einer erbarmt mir zu antworten - scheinbar bist du hier der einzigste aktive Tippgeber im Unterforum "mobile". 



schlingel hat gesagt.:


> Ein ViewFlipper kann nur 2D-Gesten. Standard ist nach links oder rechts wischen. Pinch für Zoom-In und Zoom-Out musst du dir auch selber schreiben. Bei Android 2.1 ist da noch nichts dabei, ich glaub erst ab Honeycomb. (Hier gibt's Quellen dazu.)


Aufgrund eines falschen Verständnisses vom ViewFlipper hatte ich meine Versuche mit dieser Klasse schon in die Tonne getreten und bereits nochmal von vorn mit dem LinearLayout probiert. Scheinbar hatte ich beim ersten Versuch mit dem ViewFlipper die Methode removeView() übersehen. - Ich hatte wohl Tomaten vor den Augen!
Dein Antwort hat mich dazu animiert es nochmal mit dem ViewFlipper zu probieren: und der Wechsel der Views funktioniert wunderbar! :toll:

Jetzt fehlen eigentlich nur noch 4 Dinge:
- Gestenerkennung
- große Schrift
- Animation
- Breadcrumps



schlingel hat gesagt.:


> Double Tab ditto. Wobei ich davon abraten möchte, weil das absolut außerirdisch ist auf mobilen Plattformen. Auf Android gibt's den Long-Click oder den Click. Doppelklick macht auf einem Smartphone einfach wenig Sinn. Behilf dir da lieber mit Quick-Actions.


Dies hatte ich nur mit aufgenommen, um einfach die Option zu haben.
Über die Standards bei Android kenne ich mich gar nicht aus - ich habe selber noch ein Symbian-Gerät.
Das DoubleTab hatte ich aber glaube ich schon mal in einer Apple-Werbung gesehen.



schlingel hat gesagt.:


> Was genau möchtest du den zoomen? Controls oder nur ein Bild? Controls ist generell schwierig, wenn du da eine Lösung findest wäre ich auch sehr daran interessiert.


Eigentlich überhaupt nichts. Ich hatte ja meine ViewFlipper-Versuche zunächst einmal in die Tonne getreten und mit einem sauberen neu LinearLayout angefangen. Hier muss man die Gesten scheinbar alle selber detektieren. Ich dachte mir, dass es hierzu schon etwas fertiges geben müsste und hoffte auf einen guten Link. Die vielen Gesten erwähnte ich einfach um eine gute Library für die Zukunft zu finden. Wenn aber mit Honeycomb Android dies schon von Haus aus mitbringt, dann lohnt sich der Aufwand zum Schreiben einer solchen Bibliothek wohl nicht, weshalb ich mich nur auf die aktuell benötigte Geste konzentrieren sollte: der Wisch von links nach rechts, um das vorherige Menü reinzuziehen. - Leider macht dies der ViewFlipper nicht automatisch. Ich habe auch gerade keine Idee, wie man das am sinnvollsten umsetzt. Ich arbeite aktuell mit einem LongClick, um meine Anwendung zu testen:

```
@Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        super.onInterceptTouchEvent(event);
        
        if(event.getAction() == 1) {                    // Ende einer Geste
        	long touchDown = event.getEventTime() - event.getDownTime();
            
        	if(touchDown > 1000) {                  // Nach 1s LongClick
	        	if( m_pageStack.size() > 1) {   // Nur wenn nicht im Hauptmenü
			        this.showPrevious();       // vorherigen Menüpunkt anzeigen
			        this.removeView( m_pageStack.pop() );   // altes Untermenü wieder aus dem ViewFlipper und dem Stack hauen.
	        	}
        	}
        }
        return false;
    }
```
Hast du nochmal einen Tipp für mich? 

PS: Sollte ich aber einmal in Beruhrung mit gezoomten Controls kommen, dann werde ich an dich denken! 



schlingel hat gesagt.:


> Punkto deines ViewFlipper-Problems: Vielleicht hast du mit dem ViewPager aus dem Support Package mehr Erfolg. In dem Fall hast du wieder einen Adapter der die Seiten bzw. Views für die Anzeige enthält - ähnlich dem ListView-Adapter. Dort könntest du bei dem Flip-Event die Liste manipulieren so dass sie danach aussieht wie du es brauchst.


Danke für die Info - aber der ViewFlipper schon doch geegnet zu sein.



schlingel hat gesagt.:


> Schrifttyp kannst du mit dem typeface-Attribut ändern.


Danke, das werde ich gleich als nächstes ausprobieren.

Anschließend wäre noch eine Animation wie hier nicht schlecht - allerdings waren alle Beispiel zu diesem Thema immer in Verbindung mit einem xml-Layout, was mir noch Schwierigkeiten bereitet und auch nicht wirklich zu meiner generischen Komponente passt.
Auch an dieser Stelle wäre ich über deinen Rat sehr dankbar.


PS: die Probleme mit dem Emulator bestehen wohl darin, dass die Dateien im Nutzerprofil abgelegt werden, welches auf einen Server synchronisiert wird (habe ein Domain-Nutzerkonto). Dort ist meine Quotta überschritten (nicht zuletzt wegen eben dies AVDs - ich glaube, dies verurscht die Probleme.
Lässt sich der Speicherort, wo die AVDs abgelegt werden ändern?


----------



## schlingel (14. Apr 2012)

> Das DoubleTab hatte ich aber glaube ich schon mal in einer Apple-Werbung gesehen.


Möglich, ist trotzdem absolut nicht das womit ich persönlich rechnen würde um zurück zu kommen. Außerdem ist das eine andere Plattform und kann so nicht sinnvoll nach Android überführt werden. 

Einen Tipp punkto LongClicks habe ich: die gibt's schon fix fertig. Siehe auch hier.

Punkto Animation: Wo genau hakt es denn? Animationen sind eine von den sehr wenigen für XML konzipierte Dingen in Android die sich sehr angenehm auch in Java umsetzen lassen.

Punkto Emulator: Das könntest du mit einem symbolischen Link machen. Also das .android-Verzeichnis aus deinem User-Verzeichnis irgendwohin schieben und dann einen Symlink darauf setzen damit es das SDK wieder findet.


----------



## jf (14. Apr 2012)

schlingel hat gesagt.:


> Möglich, ist trotzdem absolut nicht das womit ich persönlich rechnen würde um zurück zu kommen. Außerdem ist das eine andere Plattform und kann so nicht sinnvoll nach Android überführt werden.


Bei iOS wird es glaube ich nur dafür verwendet, um auf eine Stelle hineinzuvergrößern. Ein weiterer Doppel-Tipp verkleinert wieder auf den Ursprungs-Zoom. - Eine etwas einfachere Alternative zum Pinchen also.
Um im Menü zurück zu kommen wollte ich aber eigentlich einen Swipe verwenden. Nur weiß ich aktuell nicht so recht, wie ich das am sinnvollsten über das MotionEvent selber implementiere. - Aber du sagtest ja, dass dies vom ViewFlipper bereits unterstützt wird: vlt. gibt es daher ja eine einfachere Aternative zum Seblstimplementieren.



schlingel hat gesagt.:


> Einen Tipp punkto LongClicks habe ich: die gibt's schon fix fertig. Siehe auch hier.


Ah, ok. Das muss ich mir merken. Wobei der LongClick ja recht einfach selbst geschrieben ist.
Aber wenn es ein setOnLongClickListener() gibt, dann sollte es soch auch ein setSwipeListener() geben... oder? (werde das am Montag gleich mal überprüfen)



schlingel hat gesagt.:


> Punkto Animation: Wo genau hakt es denn? Animationen sind eine von den sehr wenigen für XML konzipierte Dingen in Android die sich sehr angenehm auch in Java umsetzen lassen.


Prima, das klinkt ja schon mal sehr gut. 
Es hakt wohl an einem Beispiel: ein Beispiel sagt mehr als 1000 Worte.
Ich finde, da sollte es mehr davon in der Doku geben.

Unter Standard-Java hätte ich jetzt im EDT über InvokeLater absolut die Position einer Komponente geändert.
Aber bei Android dürfte das so nicht gehen... Mir fehlt die Idee, wo ich den Hebel am besten ansetzen soll.



schlingel hat gesagt.:


> Punkto Emulator: Das könntest du mit einem symbolischen Link machen. Also das .android-Verzeichnis aus deinem User-Verzeichnis irgendwohin schieben und dann einen Symlink darauf setzen damit es das SDK wieder findet.


Danke für den Tipp. Werde ich mir anschauen. Habe noch nicht mit symbolischen Links gemacht - das sollte doch nur unter Vista+ funktionieren, oder?


----------



## jf (16. Apr 2012)

Hallo, ich habe jetzt ein gutes Beispiel für Gesten und Animation gefunden.
Das Beispiel selber läuft wunderbar - doch wenn ich versuche, es auf mein Projekt anzuwenden, dann klappt es nicht mehr. ???:L

Ich wollte erst einmal die Tatsch-Geste implementieren, aber bereits hier komme ich nicht weiter!
- Ich erhalte noch nicht einmal Log-Ausgaben:


```
@Override
	public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
		Log.e("FLING", "Pos1");
		return false;
	}
```

Den einzigen Unterschied zum Beispiel, welchen ich finden konnte ist folgender:

```
// Instanzierung im Beispiel:
    	gesturedetector = new GestureDetector(this, this);

    	// Instanzierung bei mir (es wird ein Fehler angezeigt, wenn ich es wie im Beispiel mach):
    	gestureDetector = new GestureDetector(this);
```
Woran liegt das denn schon wieder??? ???:L


----------



## schlingel (16. Apr 2012)

Im Beispiel wird der Konstruktur verwendet, der als zweiten Parameter einen Gesten-Listener erwartet. Läßt du deine Klasse den OnGestureListener implementieren?

Hört sich nämlich nicht so an wenn du einen Fehler bekommst.


----------



## jf (16. Apr 2012)

schlingel hat gesagt.:


> Im Beispiel wird der Konstruktur verwendet, der als zweiten Parameter einen Gesten-Listener erwartet. Läßt du deine Klasse den OnGestureListener implementieren?
> 
> Hört sich nämlich nicht so an wenn du einen Fehler bekommst.


Entschuldige bitte, dass ich vergessen habe, dies zu erwähnen... => Ja, meine Klasse implementiert OnGestureListener:

```
public class MenuView extends ViewFlipper implements OnGestureListener, OnDoubleTapListener {
```
Das ist ja gerade das, was ich nicht verstehe. Ansonsten ist nämlich alles gleich (abgesehen davon, dass ich ViewFlipper erweitere, während im Beispiel von Activity geerbt wird - aber bei haben die gleichen Interfaces) ???:L


PS:
Weil ich das Problem absolut nicht verstehe, habe ich mich zwischenzeitlich um die Animation gekümmert:
ein solches Beispiel wirkt einfach Wunder - die Animation lauft! 
Allerdings würde ich gern das Nachfedern der Animation abschalten. Wie macht man das?


----------



## schlingel (16. Apr 2012)

Ah, gleicher Fehler, anderer Parameter. Du übergibst ihm nämlich kein Context-Objekt sondern nur ein View-Objekt. Damit fängt er nichts an.

Punkto Animation: Keine Ahnung ob das überhaupt geht.


----------



## jf (16. Apr 2012)

schlingel hat gesagt.:


> Ah, gleicher Fehler, anderer Parameter. Du übergibst ihm nämlich kein Context-Objekt sondern nur ein View-Objekt. Damit fängt er nichts an.


Alles klar, so macht das ganze auch Sinn.
Ich habe es jetzt wie folgt:

```
public MenuView(Context context, MenuPage startPage) {
		super(context);
		gestureDetector = new GestureDetector(context, this);
```
Allerdings erhalte ich nach wie vor keine Logausgabe bei der Eingabe von Gesten... :bahnhof:



schlingel hat gesagt.:


> Punkto Animation: Keine Ahnung ob das überhaupt geht.


Skandal, sowas muss doch gehen... :autsch:


[EDIT]
Ich komme einfach nicht drauf. Daher poste ich mal meinen Code - vlt. sieht du ja schnell, wo Hase begraben liegt...


```
public class MenuView extends ViewFlipper implements OnGestureListener, OnDoubleTapListener {
	
    private GestureDetector gestureDetector;

	private Stack<ListViewEx<MenuEntry>> m_pageStack = null;

	private Animation aniLeftIn   = null;
	private Animation aniLeftOut  = null;
       
	private Animation aniRightIn  = null;
	private Animation aniRightOut = null;

	
	public MenuView(Context context, MenuPage startPage) {
		super(context);
		gestureDetector = new GestureDetector(context, this);
    	gestureDetector.setOnDoubleTapListener(this);
		
		ListViewEx<MenuEntry> list = new ListViewEx<MenuEntry>(context);
		list.addItems( startPage.getEntries() );
		list.setOnItemClickListener( getOnItemClickListener(context, list) );
		
		m_pageStack = new Stack<ListViewEx<MenuEntry>>();
		m_pageStack.push(list);
		
    	prepareAnimations();		
		this.addView(list);
	}
	
	private OnItemClickListener getOnItemClickListener(final Context context,
			                                           final ListViewEx<MenuEntry> list) {
		return new OnItemClickListener() {
			// When clicked, show a toast with the TextView text
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				MenuEntry item = (MenuEntry)list.getItemAtPosition(position);
				
				if( item.hasSubmenu() ) {
					ListViewEx<MenuEntry> nextView = new ListViewEx<MenuEntry>(context);
					nextView.addItems( item.getSubmenu().getEntries() );
					nextView.setOnItemClickListener( getOnItemClickListener(context, nextView) );

					m_pageStack.push(nextView);
					MenuView.this.addView(nextView);
					MenuView.this.setInAnimation(aniLeftIn);
					MenuView.this.setOutAnimation(aniLeftOut);
					MenuView.this.showNext();
				}
				
	    		Toast.makeText(context, item.toString(), Toast.LENGTH_SHORT).show();
	    	}
		};
	}

	private void prepareAnimations() {
		aniLeftIn   = new TranslateAnimation(
                      Animation.RELATIVE_TO_PARENT, +1.0f, Animation.RELATIVE_TO_PARENT,  0.0f,
                      Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,  0.0f);
                       
        aniLeftOut  = new TranslateAnimation(
                      Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT, -1.0f,
                      Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,  0.0f);
       
        aniRightIn  = new TranslateAnimation(
                      Animation.RELATIVE_TO_PARENT, -1.0f, Animation.RELATIVE_TO_PARENT,  0.0f,
                      Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,  0.0f);
                       
        aniRightOut = new TranslateAnimation(
                      Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT, +1.0f,
                      Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,  0.0f);
              
        aniLeftIn.setDuration(500);
        aniLeftIn.setInterpolator(new OvershootInterpolator());
        aniLeftOut.setDuration(500);
        aniLeftOut.setInterpolator(new OvershootInterpolator());
       
        aniRightIn.setDuration(500);
        aniRightIn.setInterpolator(new OvershootInterpolator());
        aniRightOut.setDuration(500);
        aniRightOut.setInterpolator(new OvershootInterpolator());       
	}
       
	@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
    }
    
    
    // OnGestureListener interface methods ///////////////////////////////////////

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return gestureDetector.onTouchEvent(event);
	}
    
    @Override
	public boolean onDown(MotionEvent arg0) {
    	Log.v("DEBUG", "onDown"); 
    	// Do something
    	return false;
	}

    final private int SWIPE_MIN_DISTANCE = 100;
    final private int SWIPE_MIN_VELOCITY = 100;

    private int currentview = 0;

    @Override
	public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
        Log.e("FLING", "Pos1");
        
		final float ev1x = event1.getX();
		final float ev1y = event1.getY();
		final float ev2x = event2.getX();
		final float ev2y = event2.getY();
		final float xdiff = Math.abs(ev1x - ev2x);
		final float ydiff = Math.abs(ev1y - ev2y);
		final float xvelocity = Math.abs(velocityX);
		final float yvelocity = Math.abs(velocityY);
               
		if(xvelocity > this.SWIPE_MIN_VELOCITY && xdiff > this.SWIPE_MIN_DISTANCE) {
			
			if(ev1x > ev2x) {							//Swipe Left
				Log.e("Swipe", "Left");
			} else {									//Swipe Right
				Log.e("Swipe", "Right");
			}
 			
		} else if(yvelocity > this.SWIPE_MIN_VELOCITY && ydiff > this.SWIPE_MIN_DISTANCE) {
			
			if(ev1y > ev2y) {							//Swipe Up
				Log.e("Swipe", "Up");
			} else {									//Swipe Down
				Log.e("Swipe", "Down");
			}

		}
                               
		return false;
	}

	@Override
	public void onLongPress(MotionEvent e) {
		// Do something
	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
		// Do something
		return false;
	}

	@Override
	public void onShowPress(MotionEvent e) {
		// Do something
		
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
    	Log.e("DEBUG", "onSingleTapUp"); 
		return false;
	}

	
    // OnDoubleTapListener interface methods /////////////////////////////////////
	
	@Override
	public boolean onDoubleTap(MotionEvent e) {
    	Log.e("DEBUG", "onDoubleTap"); 
		return false;
	}

	@Override
	public boolean onDoubleTapEvent(MotionEvent e) {
    	Log.e("DEBUG", "onDoubleTapEvent"); 
		return false;
	}

	@Override
	public boolean onSingleTapConfirmed(MotionEvent e) {
    	Log.e("DEBUG", "onSingleTapConfirmed"); 
		return false;
	}

}
```
[/EDIT]


----------



## jf (16. Apr 2012)

[TIPP]
*Zur Animation:*
wenn man die Zeile 
	
	
	
	





```
setInterpolator(new OvershootInterpolator());
```
 rausnimmt, dann federt die Animation nicht mehr.

*Zur Schriftgröße:*
Mit der Typeface-Klasse kommt man da nicht weiter - aber die TextView kennt eine Methode 
	
	
	
	





```
setTextSize()
```
, welche eine Zahl vom Typ 
	
	
	
	





```
float
```
 verlangt.
[/TIPP]

Mit den Gesten habert es aber leider immer noch - ich bekomme nur über die 
	
	
	
	





```
onInterceptTouchEvent
```
-Methode Reaktionen... ???:L


----------



## jf (17. Apr 2012)

Ich habe das Gesten-Problem nun gelöst: allerdings realisierte ich die Geste einfache nur mit dem _MotionEvent_ der _onInterceptTouchEvent_-Methode, wobei ich alles selbst implmentiere.

Jetzt würde ich auch gern mittels einer Geste aus einer hohen Menütiefe zurück auf die Startseite springen. Dafür muss ich mehrere Animationen hintereinander ablaufen lassen. - Aktuell laufen alle Animationen parallel ab, was nicht ganz so toll aussieht den Eindruck erweckt, dass man nur eine Seite zurück gesprungen ist. Wenn ich ein Thread.sleep() einbaue, dann pausiert die Anwendung, um letztendlich wiederum alle Animationen gleichzeitig auszuführen. Bei Swing ist das ja ähnlich: aber hier kann ich mit 
	
	
	
	





```
EventQueue.invokeLater()
```
/
	
	
	
	





```
SwingUtilities.invokeLater()
```
 das Problem lösen. - Wie macht man dies bei Android?

EDIT:
Für die BreadCrumbs habe gerade diese Klasse ausprobiert - sie scheint aber nur für Android 4 zu sein... jedenfalls bekomme ich eine Menge Fehler.
Gibt es eine Alternative, welche zu empfehlen ist? - Gibt es evtl. schon etwas ähnliches bei Android von Haus aus (aktuell entwickle ich für Android 2.1)?


----------



## schlingel (18. Apr 2012)

> Wenn ich ein Thread.sleep() einbaue, dann pausiert die Anwendung, um letztendlich wiederum alle Animationen gleichzeitig auszuführen. Bei Swing ist das ja ähnlich: aber hier kann ich mit EventQueue.invokeLater() /SwingUtilities.invokeLater() das Problem lösen. - Wie macht man dies bei Android?


Sorry, da kann ich dir leider nicht mehr helfen. Du bist jetzt bereits an der Stelle wovor ich die anfangs gewarnt habe. Hättest du das mit Activities umgesetzt wäre der normale Backbutton bereits die Lösung.

So musst dir jetzt eine Liste von Aktionen aufbauen die deine Klasse nach einander abarbeitet. Aber ohne genauen Code habe ich keine Ahnung wo genau es bei dir hakt.

Wo genau ist denn das Problem mit den BreadCrumbs? In deinem Fall sollte das doch noch einfacher sein, weil du ja programmatisch den Verlauf des Benutzers bekommst. Dann klatsch einfach oben rechts LinearView oder ähnliches hin und befüll ediese mit TextViews die im OnClick-Event zu der Seite in deinem Control hinspringen.

Und zu deiner Frage: Von Haus aus gibt's das nicht in Android 2.1.


----------



## jf (18. Apr 2012)

schlingel hat gesagt.:


> Sorry, da kann ich dir leider nicht mehr helfen. Du bist jetzt bereits an der Stelle wovor ich die anfangs gewarnt habe. Hättest du das mit Activities umgesetzt wäre der normale Backbutton bereits die Lösung.


Sicher. Aber den Zurück-Knopf mag ich eh nicht leiden: bei meinem gebrauchten Testgerät springt dieser schon nicht mehr so schnell an, wie z. B. der Suchen-Knopf rechts daneben (Verschleiß?)... 
Ich kann mein Menu über nur ein Zeile Code in jeder beliebigen ViewGroup einsetzten - dieser Vorteil ist meiner Meinung nach den Aufwand wert.

Bei Swing hätte man an dieser Stelle auch ohne Probleme mit Threads arbeiten können. Aber bei der UI-Programmierung auf Android ist dies nicht (oder zumindest nicht so einfach) möglich:

```
04-18 09:50:12.038: E/AndroidRuntime(6028): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
```




schlingel hat gesagt.:


> So musst dir jetzt eine Liste von Aktionen aufbauen die deine Klasse nach einander abarbeitet. Aber ohne genauen Code habe ich keine Ahnung wo genau es bei dir hakt.


Das ist habe ich bereits umgesetzt: dazu implementierte ich einen _AnimationListener _welcher in der _onAnimationEnd_-Mehtode die nächste Animation startet.
Funktioniert ansich auch recht gut, aber es gibt leider einen Haken: nachdem eine Zurück-Animation ausgeführt wurde, entferne ich die überflüssige View aus meinem Stack und dem ViewFlipper:

```
private void showPrevView() {
		if( m_pageStack.size() > 1) {
			MenuView.this.setInAnimation(aniPrevIn);
			MenuView.this.setOutAnimation(aniPrevOut);
			this.showPrevious();
			this.removeView( m_pageStack.pop() );
		}
	}
```
Aber bereits vor der Abarbeitung von _removeView_ feuert das _onAnimationEnd_-Ereignis, welches bereits die nächste Animation einleitet, ohne das die überflüsse View entfernt werden konnte.
Dies führt dazu, dass stets die aktuelle View nach rechts raus geschoben und der linke Nachbar hereingezogen wird und dann die rausgeschobene View nochmal über die nun aktuelle drüber gezeichnet wird, bevor die nächste Animation startet.
Diese Effekt zerstört leider das sehr angenehme Arbeiten mit den Animationen.

Die _onAnimationEnd_-Methode sieht dabei so aus (_backLoop _wird dabei auf true gesetzt, bevor die obige _showPrevView_-Methode gerufen wird):

```
public void onAnimationEnd(Animation animation) {
		if(backLoop && m_pageStack.size() > 1) {
	        this.showPrevView();
		} else {
			backLoop = false;
		}
	}
```

Es wäre genial, wenn es zur _AnimationSet_-Klasse, welche mehrere Animationen parallel abarbeitet, auch eine Klasse _SequentAnimationSet_-Klasse geben würde.

Kennst du hierzu eine Alternative oder hast do sonst noch eine Idee?




schlingel hat gesagt.:


> Wo genau ist denn das Problem mit den BreadCrumbs? In deinem Fall sollte das doch noch einfacher sein, weil du ja programmatisch den Verlauf des Benutzers bekommst. Dann klatsch einfach oben rechts LinearView oder ähnliches hin und befüll ediese mit TextViews die im OnClick-Event zu der Seite in deinem Control hinspringen.
> Und zu deiner Frage: Von Haus aus gibt's das nicht in Android 2.1.


Ich dachte, dass ich mit einer vorgefertigten Lösung ein Standard-Design erhalte.
Bei Windows gibt es ja die Visual Styles. Anwendungen die hier ein eigenes UI zeichnen finde ich dabei sehr hässlich. - Aber scheinbar darf man bei einer Android-Anwendung einen beliebigen Style wählen (zumindest erlaubte dies das grafische Layouting-Werkzeug, welches ich kurz antestete).

Außerdem erhoffte ich mir ein UI-Design, welches grafisch etwas aufwändiger und somit nicht ganz so schnell umsetzbar ist - z. B. BreadCrumbs in Pfeilform wie hier.

Da ich aber bisher nicht wirklich etwas in dieser Form fand, wollte ich es genau so umsetzen, wie du es bescheibst. Hierzu hätte ich dann aber doch noch ein...zwei Fragen:


Ich hätte an einen Button anstatt eine TextView gedacht - gibt es einen spezifischen Grund, warum du eine TextView vorziehst?
Ich würde gern links einen Home- und rechts einen Zurück-Knopf anbringen und dazwischen die Crumbs). Bei Swing wäre dies mit eine BorderLayout recht einfach umsetzbar. - Welches Equivalent gibt es bei Android?
Um das Klicken auf die Crumbs so einfach wie möglich zu gestalten, würde ich gern stets den gesamten, für die Crumbs zur Verfügung stehenden Platz ausnutzen, indem ich deren Größe dynamisch anpasse. - Gibt es hierfür bereits ein "Fill"-Attribut, damit man sich das hänsiche rechnen sparen kann?


----------



## jf (19. Apr 2012)

[TIPP]Info[/TIPP]
In einer speziellen Situation kam es durch den Aufruf einer weiteren Animation im _onAnimationEnd_-Ereignis zu einem Absturz.
(dies könnte sogar ein Bug von Android sein)

Daher musste ich die Routine wie folgt umsetzen:

```
public void onAnimationEnd(Animation animation) {
		if(backLoop && (m_pageStack.size() > 1)) {
			Handler curHandler = new Handler();
			curHandler.post(m_launchSequentAnimation);
		} else {
			backLoop = false;
		}
	}
```

Das im vorherigen Beitrag geschilderte Problem besteht aber leider nach wie vor.


Außerdem kommt ein neues Problem hinzu:
Ich habe nun meiner ListView eine andere Hintergrundfarbe verpasst. Aber leider springt diese jedes mal wieder auf schwarz zurück, sobal auf ein ListItem getippt und der Finger dann vom Item wieder weggezogen wird. Auch während der Transition-Animationen ist der ListView-Hintergrund schwarz.
Kennt jemand das Probelm und evtl. eine Lösung?

[EDIT]Dieses Problem scheint bekannt zu sein.
Aber was ist das Java-Equivalent zu 
	
	
	
	





```
android:cacheColorHint
```
?
[/EDIT]


----------



## jf (19. Apr 2012)

Mist, schon wieder die Möglichkeit zum editieren abgelaufen... 

[TIPP]Die setCacheColorHint-Methode bringt die Lösung![/TIPP]
Aber warum passiert dies nicht automatisch, wenn man eine feste Hintergrundfarbe (solid color) mittels _setBackgroundColor()_ setzt - in diesem Fall macht diese zusätzliche Einstellung doch immer Sinn! 

An dieser Stelle aber dann gleich noch eine Frage:
Kann man die Hintergrundfarbe einer View auch auslesen? - Ein _getBackgroundColor()_ kennt die ListView jedenfalls nicht... ???:L

PS: und noch eine Information zu dem Problem mit dem sequenziellen Abspielen von Animationen:
Es hat wohl doch nichts mit dem Entfernen der überschüssigen View zu tun, denn der Effekt zeigte sich auch ohne des Entfernen jener.
Soll ich mal ein kleine ausführbares Beispiel dazu basteln? - Bitte Bescheid geben, wenn sich jemand dazu bereit erklärt es sich mal anzuschauen.


----------

