Bouw een ASCII Art Editor Image Export & User Configuration

Het Android-platform biedt een breed scala aan opslagopties voor gebruik binnen uw apps. In deze tutorialserie gaan we een aantal van de gegevensopslagfaciliteiten van de Android SDK verkennen door een eenvoudig project te bouwen: een ASCII-kunsteditor.

In het eerste deel van deze serie hebben we onze gebruikersinterface-elementen gemaakt, waaronder een hoofdactiviteit met een tekstveld voor gebruikers om hun tekens in te voeren en een configuratie-activiteit waarin de gebruiker kleurinstellingen kan kiezen. In deze aflevering gaan we deze keuze voor gebruikersconfiguratie implementeren en gebruikers toestaan ​​hun kunstwerken als PNG-afbeeldingen te exporteren, waarbij de resulterende bestanden worden opgeslagen in de externe map Afbeeldingen op de SD-kaart. In de laatste twee delen van de serie werken we met een SQLite-database om de illustraties van de gebruiker op te slaan, te laden en te verwijderen.

De omtrek voor deze reeks is als volgt:

  • De gebruikersinterface bouwen
  • Afbeelding exporteren en gebruikersconfiguratie
  • Database maken & opvragen
  • Opslaan en verwijderen van ASCII-afbeeldingen

Stap 1: Reageren op de knop Instellingen Klik op

Laten we beginnen met de gebruikersconfiguratie-instellingen. In de hoofdactiviteit van uw app, vóór de onCreate methode, voeg een variabele toe om het bewerkbare tekstveld weer te geven:

 privé EditText textArea;

U moet een import toevoegen:

 importeer android.widget.EditText;

Binnen onCreate, nadat u de inhoudsweergave hebt ingesteld, haalt u een verwijzing naar het tekstveld op, zodat we de weergave-instellingen kunnen toepassen:

 textArea = (EditText) findViewById (R.id.ascii_text);

Dit is de ID die we het bewerkbare tekstveld hebben gegeven in het XML-lay-outbestand. Download vervolgens een verwijzing naar de knop Instellingen en klik op klikken:

 KnopsetBtn = (Knop) findViewById (R.id.set_colors_btn); setBtn.setOnClickListener (deze);

U heeft de volgende import nodig toegevoegd:

 importeer android.widget.Button;

Verleng de openingslijn van uw activiteitsklasseopgave om klikken als volgt te verwerken:

 public class MainActivity breidt activiteit uit OnClickListener 

Wijzig de klassenaam als u een andere naam kiest. Dit vereist een nieuwe import:

 import android.view.View.OnClickListener;

Nu moet je klas de bij klikken methode, dus voeg het toe na de onCreate methode:

 openbare ongeldig onClick (View v) 

Deze methode gaat verschillende knopklikken aan, dus we zullen er tijdens de reeks code aan toevoegen. U heeft de volgende import nodig:

 import android.view.View;

Binnen in de bij klikken methode, moeten we afstemmen wat er gebeurt met de knop waarop is geklikt, omdat we er meer dan één behandelen:

 if (v.getId () == R.id.set_colors_btn) 

Dit is de knop Instellingen die we de vorige keer in ons hoofdlay-outbestand hebben opgenomen.


Stap 2: start de instellingenactiviteit

We hebben de activiteit gemaakt om de gebruikersconfiguratie de laatste keer af te handelen, dus laten we beginnen met het uitvoeren vanaf onze hoofdactiviteit, binnen de bij klikken "als" -instructieblok:

 Intent colorIntent = new Intent (this, ColorChooser.class); this.startActivityForResult (colorIntent, COLOR_REQUEST);

U hebt deze import nodig:

 importeer android.content.Intent;

We starten een intentie voor de activiteit die we hebben gemaakt om de keuze van het gebruikerskleurenschema af te handelen. In die activiteit gaan we de gebruiker een optie laten kiezen en het resultaat teruggeven aan de hoofdactiviteit. Daarom gebruiken we dit startActivityForResult. We zullen het resultaat ophalen in de onActivityResult methode die we hierna zullen toevoegen. Maar eerst moeten we kunnen identificeren van welke activiteit we terugkeren, dus we geven een constante door als de tweede parameter voor de startActivityForResult methode. Voeg de constante toe aan de bovenkant van uw klassedeclaratie, vóór de onCreate methode:

 private finale int COLOR_REQUEST = 1;

Voeg nu de onActivityResult methode na de bij klikken methode:

 protected void onActivityResult (int requestCode, int resultCode, Intent data) 

Binnen deze klasse zullen we omgaan met gegevens die worden geretourneerd via de Settings chooser Activity (en later vanuit de activiteit waarbij de gebruiker een opgeslagen afbeelding kiest om te laden). Controleer binnen de methode of we terugkeren van de Color Chooser Activity en of we een geldig resultaat hebben:

 if (requestCode == COLOR_REQUEST) if (resultCode == RESULT_OK) 

Wanneer de gebruiker op de knop Instellingen klikt, wordt de activiteit Activiteit van de kiezer gestart. De gebruiker kiest een kleurenschema en de Chooser-activiteit wordt voltooid, waarbij gegevens die de gebruikerskeuze vertegenwoordigen worden weergegeven in de hoofdactiviteit, omdat hier de activiteit Kiezer is gestart. Bij terugkeer naar de hoofdactiviteit, de onActivityResult methode wordt uitgevoerd, zodat we de gebruikerskeuze hier kunnen implementeren (wat we binnenkort zullen doen).


Stap 3: Detecteer keuzes van gebruikersinstellingen

Laten we nu onze aandacht richten op de Chooser Activity waarin de gebruiker een kleurenschema selectie kan maken. Open uw "ColorChooser" -activiteit. De onCreate methode zou al voltooid moeten zijn. Houd er rekening mee dat toen we de afbeeldingsknoppen die elk kleurenschema vertegenwoordigen, hebben toegevoegd aan het XML-lay-outbestand 'color_choice', we 'setColors' hebben opgegeven als hun bij klikken attribuut en bevatte een tag die de twee HEX-kleuren voor tekst en achtergrond vertegenwoordigt - bekijk nu de "color_choice.xml" markup om dit te controleren. Wanneer gebruikers op de afbeeldingenknoppen klikken, voert Android de opgegeven methode uit in de activiteit die de lay-out host. Voeg de methode toe aan uw "ColorChooser" -activiteit na onCreate:

 public void setColors (bekijk weergave) 

Voeg de volgende invoer toe aan de klas:

 import android.view.View; importeer android.content.Intent;

Binnen de "setColors" -methode, haalt u eerst de tag op uit de weergave waarop is geklikt:

 String tagInfo = (String) view.getTag ();

De tag heeft de volgende notatie: "# 000000 #ffffff" - deel de twee kleuren in een String-array:

 String [] tagColors = tagInfo.split ("");

Nu willen we deze gegevens teruggeven aan de hoofdactiviteit, zodat we de kleurenschema-instellingen kunnen toepassen op de elementen van de gebruikersinterface. Om dit te doen gebruiken we een intentie:

 Intent backIntent = new Intent ();

Voeg de twee kleuren toe als extra gegevens:

 backIntent.putExtra ("textColor", tagColors [0]); backIntent.putExtra ("backColor", tagColors [1]);

De eerste kleur staat voor de tekst en de tweede voor de achtergrond. Stel het retour Intent resultaat in:

 setResult (RESULT_OK, backIntent);

Ga terug naar de activiteit die deze heeft genoemd door te eindigen:

 af hebben();

De twee HEX-kleurstrings worden doorgegeven aan de onActivityResult methode in de hoofdactiviteitsklasse.


Stap 4: Pas het kleurenschema toe

Terug in je hoofdactiviteit onActivityResult methode, in de twee "if" -instructieblokken die we hebben toegevoegd om retouren van de chooser-activiteit te detecteren, haal je de strings terug die we hebben doorgegeven:

 String selectedTextColor = data.getStringExtra ("textColor"); String selectedBackColor = data.getStringExtra ("backColor");

Laten we een hulpmethode gebruiken om de kleuren in te stellen, zodat we hetzelfde proces elders kunnen uitvoeren:

 updateColors (selectedTextColor, selected BackColor);

Voeg de helpermethode toe na de onActivityResult methode:

 private void updateColors (String tColor, String bColor) 

Binnen deze methode kunnen we nu de kleuren instellen voor de bewerkbare tekstveldtekst en achtergrond:

 textArea.setTextColor (Color.parseColor (TColor)); textArea.setBackgroundColor (Color.parseColor (bColor));

Dit vereist een nieuwe import:

 importeer android.graphics.Color;

Stap 5: werk de gedeelde voorkeuren bij

We hebben het uiterlijk van het tekstveld aangepast aan de keuze van de gebruiker, maar we willen de keuze onthouden, zodat elke keer dat ze de app uitvoeren, deze zal worden nageleefd. Laten we een instantievariabele aan de bovenkant van de klasse toevoegen, zodat we overal naar de gedeelde voorkeuren kunnen verwijzen:

 private SharedPreferences asciiPrefs;

Voeg indien nodig de import toe:

 importeer android.content.SharedPreferences;

In onCreate, na de bestaande code krijgt u de gedeelde voorkeuren met een naam naar keuze (u moet dezelfde naam gebruiken telkens wanneer u de voorkeuren in uw app ophaalt):

 asciiPrefs = getSharedPreferences ("AsciiPicPreferences", 0);

Terug in de onActivityResult methode, nadat u de helpermethode hebt aangeroepen, krijgt u de editor voor gedeelde voorkeuren:

 SharedPreferences.Editor prefsEd = asciiPrefs.edit ();

Geef de gegevens door die de keuze van de gebruiker vertegenwoordigen en verbind deze met de voorkeuren van de app:

 prefsEd.putString ("colors", "" + chosenTextColor + "" + chosenBackColor); prefsEd.commit ();

We specificeren een naam voor het voorkeursgegevensitem en geven de twee aaneengeschakelde strings door tot één, met een spatie ertussen. Dit is een typisch gebruik van gedeelde voorkeuren, die zijn bedoeld voor sleutel / waarde-paren van primitieve typewaarden, dus worden deze vaak gebruikt voor configuratie-instellingen.


Stap 6: Controleer de gedeelde voorkeuren

We willen dat de gebruiker het door haar gekozen kleurenschema ziet wanneer ze de app in de toekomst gebruiken, dus we moeten hun keuze controleren wanneer de activiteit start. In de onCreate methode, na het ophalen van de gedeelde voorkeuren:

 String selectedColors = asciiPrefs.getString ("colors", "");

We passeren de sleutelreeks die we hebben gebruikt bij het opslaan van de gebruikerskeuze. De gebruiker heeft mogelijk nog geen voorkeur opgeslagen, dus gebruik de kleurinstellingen in een voorwaardelijke verklaring:

 if (chosenColors.length ()> 0) String [] prefColors = chosenColors.split (""); updateColors (prefColors [0], prefColors [1]); 

We splitsen de kleurreeks opnieuw en bellen de hulpmethode om de instellingen toe te passen.


Stap 7: Behandel knopklikken exporteren

Vergeet niet dat we een knop Exporteren hebben toegevoegd voor gebruikers om hun illustraties als afbeeldingsbestanden op te slaan. In je hoofdactiviteit onCreate methode, klikken daarop detecteren:

 Knop saveImgBtn = (Button) findViewById (R.id.export_btn); saveImgBtn.setOnClickListener (deze);

Voeg nu een "else if" in de bij klikken methode:

 else if (v.getId () == R.id.export_btn) saveImg (); 

Dit wordt een andere helpermethode, dus voeg het toe aan je klassenbestand na de "updateColors" -methode:

 private void saveImg () 

Stap 8: Beschikbaarheid externe opslag

Het Android-systeem kan op veel verschillende apparaten worden gebruikt en we kunnen niet alles aannemen wat voor faciliteiten de gebruiker heeft. Voordat u iets naar externe opslag probeert te schrijven, moet u eerst controleren of het beschikbaar is. Binnen de nieuwe helpermethode voegt u een controle toe op de opslagstatus van de gebruiker met behulp van de omgeving:

 String state = Environment.getExternalStorageState ();

U hebt hiervoor een import nodig:

 import android.os.Environment;

Voeg nu een voorwaardelijke test toe over het resultaat, zodat we kunnen aanpassen wat er hierna gebeurt:

 if (Environment.MEDIA_MOUNTED.equals (state))  else 

Het "als" -blok exporteert de afbeelding naar externe opslag, met de "anders" -blokafhandelingssituaties waarin geen opslagruimte beschikbaar is. In een dergelijk geval is alles wat we willen doen een foutmelding schrijven aan de gebruiker door hem te laten weten dat we de afbeelding niet kunnen exporteren - in het "else" -blok:

 Toast.makeText (this.getApplicationContext (), "Sorry - u hebt geen externe" + "opslagdirectory beschikbaar!", Toast.LENGTH_SHORT) .show ();

Voeg de vereiste import toe:

 import android.widget.Toast;

Stap 9: exporteer het afbeeldingsbestand

Laten we nu de gevallen behandelen waarin externe opslag beschikbaar is. Voeg de volgende imports toe voor de uitvoer van het bestand:

 importeer java.io.File; importeer java.io.FileOutputStream; importeer java.util.Date; importeer android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat;

Terug in de hulpmethode voor het opslaan van afbeeldingen, haalt u in het "als" -blok een verwijzing op naar de map Afbeeldingen:

 Bestand picDir = Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_PICTURES);

Nu hebben we het eerste deel van het pad dat we zullen gebruiken om het afbeeldingsbestand te maken. De afbeelding bevat de zichtbare inhoud van het bewerkbare tekstveld, inclusief de achtergrondkleur, dat wil zeggen dat deze afbeelding weergeeft wat u kunt zien wanneer u het app-scherm exporteert. Om dit te bereiken gebruiken we de cache voor de weergave:

 textArea.setDrawingCacheEnabled (true); textArea.buildDrawingCache (true); Bitmap bitmap = textArea.getDrawingCache ();

Hiermee stelt u de bewerkbare tekstveldweergave in die als tekenbaar moet worden weergegeven en wordt het huidige uiterlijk als een bitmap opgeslagen met behulp van de tekencache..

Nu moeten we ons bestand een naam geven, dus laten we de huidige datum en tijd gebruiken om elk bestand uniek te maken, door wat informatieve tekst en de extensie van het beeldbestand toe te voegen:

 Date theDate = new Date (); String fileName = "asciipic" + theDate.getTime () + ". Png";

Hier geven we de bestandsnaam op, laten we nu het bestand samen gebruiken met het pad naar de map Afbeeldingen:

 Bestand picFile = nieuw bestand (picDir + "/" + bestandsnaam);

Omdat we een aantal bestands-I / O gaan doen die we nodig hebben proberen en vangst blokken:

 probeer  catch (Uitzondering e) e.printStackTrace (); 

Hierdoor kan het programma blijven draaien als er iets misgaat met de invoer / uitvoerbewerkingen. Binnen in de proberen blokkeren, maak het bestand aan en geef het door aan een uitvoerstroom:

 picFile.createNewFile (); FileOutputStream picOut = new FileOutputStream (picFile);

Comprimeer de bitmap en schrijf deze naar de uitvoerstroom en sla het resultaat op als een boolean:

 boolean werkte = bitmap.compress (CompressFormat.PNG, 100, picOut);

Geef een bericht aan de gebruiker, afhankelijk van het resultaat van de schrijfbewerking:

 if (werkt) Toast.makeText (getApplicationContext (), "Afbeelding opgeslagen in de afbeeldingenlijst van uw apparaat" + "!", Toast.LENGTH_SHORT) .show ();  else Toast.makeText (getApplicationContext (), "Whoops! File not saved.", Toast.LENGTH_SHORT) .show (); 

Sluit nu het bestand:

 picOut.close ();

We kunnen de bronnen vrijmaken die worden gebruikt voor de tekencache, na de vangst blok:

 textArea.destroyDrawingCache ();

Dat is de bestandsuitvoerbewerking voltooid. De gebruiker kan de geëxporteerde illustraties als afbeelding bekijken door op elk gewenst moment naar de map Afbeeldingen van het apparaat te bladeren.

Tip:Als u uw app op de emulator in Eclipse gebruikt, kunt u deze zo instellen dat deze externe opslag bevat door de AVD te bewerken en de hoeveelheid opslagruimte in het veld "Grootte" van de SD-kaart in te voeren. Zodra de AVD is gestart, voert u uw app daarop uit en exporteert u een afbeelding. Open in Eclipse het DDMS-perspectief vanuit het menu Venster openen. Selecteer het apparaat en blader naar de map Afbeeldingen (mnt / sdcard / Afbeeldingen). U zou alle afbeeldingen moeten zien die door de app in deze map zijn geschreven. Als u er een wilt ophalen van het virtuele apparaat, selecteert u het en klikt u op de knop "Een bestand uit het apparaat trekken" om het op te slaan en op uw computer te bekijken.

Conclusie

Dat is het gebruikersconfiguratie- en beeldexportgedeelte van de app. Als u de app nu uitvoert, moet u het kleurenschema kunnen instellen en afbeeldingen naar de SD-kaart kunnen exporteren (mits er een aanwezig is). Controleer de download van de broncode als je ergens niet zeker van bent. We hebben externe opslag en gedeelde voorkeuren gebruikt in deze zelfstudie. In de volgende delen zullen we een SQLite-database bouwen met behulp van inserts, query's en updates om de gebruiker te helpen bij het opslaan, laden, verwijderen en bewerken van zijn ASCII-kunstwerken.