Dynamische Markierung "auf" einem Image

  • Antworten:12
  • Bentwortet
LitteM
  • Forum-Beiträge: 141

28.03.2013, 22:24:32 via Website

Hallo zusammen.

Was will ich machen? Einen Punkt/Kreis/Markierung dynamisch über eine ImageView bewegen.

Was ich bisher an Code zusammengebastelt habe:
Ich rufe mir ein Bild als ImageView auf, das ich über fill_parent auf den ganzen Bildschirm werfe.
Danach rufe in meiner Main einen Intent auf, der mir einen Kreis (über canvas, s. Code unten) zeichnet und über onTouch meinem Finger folgt.
Dem Intent habe ich ein Style zugeordnet der mir den Intent transparent darstellt damit man die Karte aus der Main noch sieht.

Mein Problem hierbei: Die Fläche die Canvas nutzt/zur Verfügung steht um darauf zu zeichnen, würde ich gerne genau gleich der größe der Karte/des ImageViews setzen.

Ist das mit meinem Ansatz überhaupt möglich oder gibt es da eine bessere einfachere Variante? Bisher wollte nichts was ich ausprobiert habe so richtig funktionieren. Um später einen Punkt auf der Karte über Koordinatenrichtig darzustellen muss das zwingend zusammenpassen...

Danke im Vorraus für Hilfe :)

Activity im Manifest:

1<activity android:name=".ShowPosition"
2 android:screenOrientation="landscape"
3 android:theme="@style/Theme.Transparent"></activity>

Layout XML:
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7 <Button
8 android:id="@+id/map"
9 android:layout_width="wrap_content"
10 android:layout_height="wrap_content"
11 android:text="Beenden" />
12
13 <ImageView
14 android:id="@+id/my_image"
15 android:layout_width="fill_parent"
16 android:layout_height="fill_parent" />
17</LinearLayout>

Intent der Main:
1Intent showPosition = new Intent(MainActivity.this, ShowPosition.class);
2 startActivity(showPosition);

Style XML:
1<?xml version="1.0" encoding="utf-8"?>
2<resources>
3 <style name="Theme.Transparent" parent="android:Theme">
4 <item name="android:windowIsTranslucent">true</item>
5 <item name="android:windowBackground">@android:color/transparent</item>
6 <item name="android:windowContentOverlay">@null</item>
7 <item name="android:windowNoTitle">true</item>
8 <item name="android:windowIsFloating">true</item>
9 <item name="android:backgroundDimEnabled">false</item>
10 </style>
11</resources>

Canvas Klasse:

1package com.example.mapapplication;
2
3import android.app.Activity;
4import android.content.Context;
5import android.content.Intent;
6import android.graphics.Bitmap;
7import android.graphics.BitmapFactory;
8import android.graphics.Canvas;
9import android.graphics.Color;
10import android.graphics.Paint;
11import android.graphics.PointF;
12import android.os.Bundle;
13import android.os.Environment;
14import android.util.Log;
15import android.view.MotionEvent;
16import android.view.View;
17
18public class ShowPosition extends Activity {
19 @Override
20 protected void onCreate(Bundle savedInstanceState) {
21 super.onCreate(savedInstanceState);
22 setContentView(new SampleView(this));
23
24 }
25 private class SampleView extends View {
26
27 private boolean isDrawing;
28 private PointF endPoint;
29 private Paint p;
30
31 public SampleView(Context context) {
32 super(context);
33 setFocusable(true); initalize();
34 }
35
36 private void initalize(){
37 p = new Paint();
38 p.setAntiAlias(true);
39 p.setColor(Color.RED);
40 p.setStyle(Paint.Style.STROKE);
41 p.setStrokeWidth(4.5f);
42 p.setAntiAlias(true);
43 }
44
45 @Override
46 protected void onDraw(Canvas canvas) {
47
48 if(isDrawing)
49 canvas.drawCircle(endPoint.x, endPoint.y, 50, p);
50 }
51
52
53 public boolean onTouchEvent(MotionEvent event) {
54
55 switch (event.getAction())
56 {
57 case MotionEvent.ACTION_DOWN:
58 endPoint = new PointF();
59 isDrawing = true;
60 break;
61
62 case MotionEvent.ACTION_MOVE:
63 if(isDrawing)
64 {
65 endPoint.x = event.getX();
66 endPoint.y = event.getY();
67 invalidate();
68 break;
69 }
70
71 case MotionEvent.ACTION_UP:
72 if(isDrawing)
73 {
74 endPoint.x = event.getX();
75 endPoint.y = event.getY();
76 invalidate();
77 isDrawing = false;
78 break;
79 }
80 }
81 return true;
82 }
83 }
84}

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

28.03.2013, 23:00:50 via Website

Mein Problem hierbei: Die Fläche die Canvas nutzt/zur Verfügung steht um darauf zu zeichnen, würde ich gerne genau gleich der größe der Karte/des ImageViews setzen.

Gibt es einen konkreten Grund für den Ansatz mit 2 Activities?
Kommt mir so erstmal wie von hinten durch die Brust ins Auge vor ;-)

Spontan würde ich das gemäß obiger Vorgabe so angehen, das ich in einem Layout ein Canvas mit Hintergrundbild (deine Karte) verwende, oder ein Framelayout mit deinem ImageView und einem Canvas darin (wenn die Existenz eines ImageView irgendeine Relevanz besitzt)
.

LitteM

Antworten
LitteM
  • Forum-Beiträge: 141

28.03.2013, 23:12:26 via Website

Ich wollte etwas Code "auslagern". In meiner Main lade ich die Karte mit AsyncTask runter. Später möchte ich über die Main eine Funktion aufrufen, die mir Koordinaten herholt und danach die Funktion für die grafische Darstellung der Karte/Position (wie das genau aussehen soll ist denke ich jetzt noch uninteressant). Die Darstellung der Position auf der Karte hätte ich dann auch gerne in einer extra Sektion gepackt. Quasi drei große Blöcke damit ich nicht eine ultra lange *.java Datei habe. Falls das so machbar wäre. Die Karte lade ich als png/jpg vom Server. Daher dachte ich ImageView macht sinn.


Mit einem Canvas Hintergrundbinld hatte ich mich schonmal versucht, aber das wollte bei mir nicht funktionieren :(
Ein Framelayout hatte ich auch schonmal angetestet, aber da habe ich das Canvas nicht integriert bekommen.

Und bei dem Beispiel von oben bin ich eben jetzt gelandet ;)

Hast du mir ein funktionierendes Beispiel wie ich eins von deinen zwei realisieren kann? Klingen nämlich beide einfacher aber bisher hats nich klappen wollen.

Grüße


impjor
Ändere doch einfach die Breite , Höhe deiner eigenen View auf MATCH_PARENT.
Gruß

Verstehe leider nicht so ganz genau was du meinst...
Ich hatte es hierüber versucht, allerdings hat sich da gar nichts getan:
1this.requestWindowFeature(Window.FEATURE_NO_TITLE);
2 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
3 WindowManager.LayoutParams.FLAG_FULLSCREEN);
4
5 SampleView sampleView = new SampleView(this);
6 setContentView(sampleView);

— geändert am 28.03.2013, 23:20:56

Antworten
LitteM
  • Forum-Beiträge: 141

29.03.2013, 00:50:13 via Website

Ein kleiner Fortschritt. Habe mich nochmal an Canvas über Canvas versucht. Mittlerweile kann ich drüberzeichnen. Allerdings ist meine "Karte" noch etwas arg klein. Wenn ich die noch auf Vollbild bringen könnte wärs ideal.

1package com.example.canvas;
2
3import android.app.Activity;
4import android.content.Context;
5import android.graphics.Bitmap;
6import android.graphics.BitmapFactory;
7import android.graphics.Canvas;
8import android.graphics.Color;
9import android.graphics.Paint;
10import android.graphics.PointF;
11import android.graphics.drawable.Drawable;
12import android.os.Bundle;
13import android.os.Environment;
14import android.view.MotionEvent;
15import android.view.View;
16import android.view.Window;
17import android.view.WindowManager;
18
19public class MainActivity extends Activity {
20 /** Called when the activity is first created. */
21 @Override
22 public void onCreate(Bundle savedInstanceState) {
23 super.onCreate(savedInstanceState);
24
25 this.requestWindowFeature(Window.FEATURE_NO_TITLE);
26 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
27 WindowManager.LayoutParams.FLAG_FULLSCREEN);
28
29 myView test = new myView(this);
30 setContentView(test);
31 }
32
33 private class myView extends View{
34
35 private boolean isDrawing;
36 private PointF endPoint;
37 private boolean backgroundSet;
38
39
40
41public myView(Context context) {
42 super(context);
43
44 }
45
46@Override
47protected void onDraw(Canvas canvas) {
48
49 // if(!backgroundSet)
50 background(canvas);
51
52 Paint myPaint = new Paint();
53 myPaint.setColor(Color.RED);
54 myPaint.setStyle(Paint.Style.STROKE);
55 myPaint.setStrokeWidth(3);
56
57
58 if(isDrawing)
59 canvas.drawCircle(endPoint.x, endPoint.y, 50, myPaint);
60 }
61
62private boolean background(Canvas canvas){
63
64 String imagePath = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.example.broadcast/files/test.png";
65 BitmapFactory.Options options;
66 options = new BitmapFactory.Options();
67 options.inSampleSize=1;
68 Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
69 canvas.drawBitmap(bitmap, 0, 0, null);
70
71 backgroundSet=true;
72 return backgroundSet;
73}
74
75public boolean onTouchEvent(MotionEvent event) {
76
77 switch (event.getAction())
78 {
79 case MotionEvent.ACTION_DOWN:
80 endPoint = new PointF();
81 isDrawing = true;
82 invalidate();
83 break;
84
85 case MotionEvent.ACTION_MOVE:
86 if(isDrawing)
87 {
88 endPoint.x = event.getX();
89 endPoint.y = event.getY();
90 invalidate();
91 break;
92 }
93
94 case MotionEvent.ACTION_UP:
95 if(isDrawing)
96 {
97 endPoint.x = event.getX();
98 endPoint.y = event.getY();
99 isDrawing = false;
100 break;
101 }
102 }
103return true;
104}
105 }
106}

Antworten
LitteM
  • Forum-Beiträge: 141

29.03.2013, 01:02:55 via Website

Gelöst :))))

Habe die Bitmap genommen und über den einzeiler auf die Bildschirmauflösung gesetzt.
--> Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, sx, sy, false);

1String imagePath = Environment.getExternalStorageDirectory().toString()+"/Android/data/com.example.broadcast/files/test.png";
2 BitmapFactory.Options options;
3 options = new BitmapFactory.Options();
4 options.inSampleSize=1;
5 Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
6 Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, sx, sy, false);
7 canvas.drawBitmap(resizedBitmap, 0, 0, null);

Die Bildschirmgröße habe ich mir so besorgt:

1Display display = getWindowManager().getDefaultDisplay();
2 Point size = new Point();
3 display.getSize(size);
4 sx= size.x;
5 sy= size.y;

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

29.03.2013, 10:59:34 via Website

Gelöst
Prima :)

Anmerkungen dazu:
- das Bild bei jeder Zeichenoperation neu zu laden ist kaum erforderlich, das könntest du auch einmal im Kontruktor machen, oder?
- deine Art der Skalierung verzerrt das Bild, wenn dessen Seitenverhältnis nicht dem des Gerätebildschirms entspricht, oder übersehe ich da etwas?

Antworten
LitteM
  • Forum-Beiträge: 141

29.03.2013, 16:40:50 via Website

Ich gebe dir bei beidem natürlich recht.

Über den ersten Punkt hatte ich mir gestern (Bin momentan in den USA - Zeitverschiebung von 9 nach DE) geschon gedanken gemacht.
Wenn ich mich jetzt nicht irre zeichne ich alles auf ein canvas und "übermale" lediglich immer die Stelle des ersten Bildes, auf die ich den Punkt setze.
Sobald ich hier mit
1canvas.drawColor(Color.TRANSPARENT);
oder ähnlichem komme ändert das leider nichts..

Bezüglich der Realisierung des unverzerrten resiz'en meiner Bitmap muss ich mir noch gedanken machen. Da ich ihr aber jegliche Koordinaten verabreichen kann ist das wohl nur ein mathematischer Abgleich um welchen Faktor ich die originale Länge oder Breite vergrößern darf, ohne die Bildschirmgrenze zu überschreiten. Zumindest war das mein Denkansatz. --> Bildschirmgröße (länge/breite) = Bitmap(länge/breite)*Faktor
Sobald der erste Werte (länge oder breite) multipliziert mit faktor die Bildschirmgröße erreicht wäre somit die Berechnung fertig.
Denkste das würd so funktionieren/okay sein?

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

29.03.2013, 17:54:56 via Website

Wenn ich mich jetzt nicht irre zeichne ich alles auf ein canvas und "übermale" lediglich immer die Stelle des ersten Bildes, auf die ich den Punkt setze.

Dem würde ich zustimmen;
was ich meinte war aber nicht, das du dir das Neuzeichen sparen kannst, sondern das Neuladen vor jedem Malzyklus.


Da ich ihr aber jegliche Koordinaten verabreichen kann ist das wohl nur ein mathematischer Abgleich

Genau, und ich seh' schon, das du das Ermitteln des korrekten Faktors wohl hinbekommen wirst ;-)

Antworten
LitteM
  • Forum-Beiträge: 141

29.03.2013, 18:13:58 via Website

Da hast du vollkommen recht. Habe das Laden der Bitmap in die onCreate verschoben und zugänglich für alle Methoden gemacht :)

Noch eine generelle Frage. Wenn ich die options bei der Bitmapfactory auf 1 setze, kann ich davon ausgehen dass mir bitmap.getWidth() bzw bitmap.getHeight() die originale Größe des Images gibt?

Damit kann ich die Bitmap recht easy auf den größtmöglichen ganzzahligen Faktor größer machen ohne die Bildschirmmaße zu überschreiten.
Ich denke ich werds so anpassen, dass ich noch eine Kommastelle mit dazunehme.

1int breite = bitmap.getWidth();
2 int höhe = bitmap.getHeight();
3
4 faktorX = sx/breite;
5 faktorY = sy/höhe;
6
7 if(faktorX>=faktorY){
8 sx= breite*faktorY;
9 sy= höhe*faktorY;
10 }
11 else{
12 sx= breite*faktorX;
13 sy= höhe*faktorX;
14 }
15
16
17 Log.d("BITMAP", "Breite/Höhe Bitmap: "+breite+ " "+ höhe+" Breite/Höhe resized: "+sx+" "+sy+" Faktor: " + faktorX+" "+faktorY);

Log ergibt mir dann:
103-29 10:18:08.127: D/BITMAP(5773): Breite/Höhe Bitmap: 940 485 Breite/Höhe resized: 1880 970 Faktor: 2 2


/Nachtrag: Skalieung um Faktor mit einer Nachkommastelle funktioniert :)

— geändert am 29.03.2013, 18:48:38

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

29.03.2013, 19:19:20 via Website

Prima, dann ist das jetzt fertig, oder?

Antworten
LitteM
  • Forum-Beiträge: 141

29.03.2013, 19:23:32 via Website

Ja. Der Block wäre damit abgehakt :)

Der nächste Arbeitspunkt ist ein Broadcast über die Wlan Schnittstelle. Denke das wird nicht leicht werden. Falls du Infomaterial dazu hast: feel free to mail me ;)

Antworten
San Blarnoi
  • Forum-Beiträge: 2.545

29.03.2013, 19:33:54 via Website

Damit habe ich mich noch nicht befasst, aber wenn du dich informiert hast, darfst du die werten Mitleser hier gerne teilhaben lassen ;-)

Antworten