Introduksjon til de nye Lollipop Activity Transitions

Hva du skal skape

Introduksjon

En av de mest interessante aspektene ved Material Design-spesifikasjonene er den visuelle kontinuiteten mellom aktivitetene. Med bare noen få linjer med kode, gir de nye Lollipop-APIene deg en meningsfull overgang mellom to aktiviteter, takket være sømløse og kontinuerlige animasjoner. Dette bryter de klassiske aktivitetsgrensene til tidligere Android-versjoner og lar brukeren forstå hvordan elementene går fra ett punkt til et annet.

I denne opplæringen vil jeg vise deg hvordan du oppnår dette resultatet, og gjør en prøveapplikasjon i samsvar med Googles retningslinjer for materialdesign.

Forutsetninger

I denne opplæringen antar jeg at du allerede er kjent med Android-utvikling, og at du bruker Android Studio som din IDE. Jeg bruker Android-intensjoner i stor utstrekning, forutsatt at det er grunnleggende kunnskaper om aktivitetslivssyklusen og den nye RecyclerView widget introdusert med API 21, siste juni. Jeg kommer ikke til å dykke inn i detaljene i denne klassen, men hvis du er interessert, kan du finne en flott forklaring i denne Tuts + opplæringen.

1. Opprett den første aktiviteten

Den grunnleggende strukturen i søknaden er rettferdig. Det er to aktiviteter, en hoveddel, MainActivity.java, hvis oppgave det er å vise en liste over elementer, og en annen, DetailActivity.java, som vil vise detaljene til elementet valgt i forrige liste.

Trinn 1: Den RecyclerView Widget

For å vise listen over elementer, vil hovedaktiviteten bruke RecyclerViewwidget introdusert i Android Lollipop. Det første du må gjøre er å legge til følgende linje i avhengig delen i prosjektets build.grade fil for å aktivere bakoverkompatibilitet:

kompilere 'com.android.support:recyclerview-v7:+'

Trinn 2: Data Definisjon

For korthets skyld vil vi ikke definere en faktisk database eller en tilsvarende datakilde for søknaden. I stedet vil vi bruke en egendefinert klasse, Ta kontakt med. Hvert element vil ha et navn, en farge og grunnleggende kontaktinformasjon knyttet til den. Dette er hva implementeringen av Ta kontakt med klassen ser ut som:

offentlig klasse Kontakt // Feltene knyttet til privatpersonens endelige sluttstreng mName, mPhone, mEmail, mCity, mColor; Kontakt (Strenge navn, String farge, String telefon, String e-post, String by) mName = navn; mColor = farge; mPhone = telefon; mEmail = email; mCity = by;  // Denne metoden gjør det mulig å få elementet tilknyttet et bestemt ID, // unikt generert ved metoden getId definert under offentlig statisk kontakt GetItem (int id) for (Kontaktpunkt: KONTAKTER) hvis (item.getId () == id) return item;  returnere null;  // siden mName og mPhone kombinert er helt unikt, // vi trenger ikke å legge til et annet id-felt offentlig int getId () return mName.hashCode () + mPhone.hashCode ();  offentlig statisk enum Felt NAME, FARGE, TELEFON, EMAIL, STAD offentlig String få (Felt f) bytte (f) tilfelle FARGE: returner mColor; tilfelle PHONE: returner mPhone; sak EMAIL: returner mEmail; sak CITY: retur mCity; tilfelle NAME: default: return mName; 

Du vil ende opp med en fin container for informasjonen du bryr deg om. Men vi må fylle den med noen data. På toppen av Ta kontakt medklasse, legg til følgende stykke kode for å fylle ut datasettet.

Ved å definere dataene som offentlig og statisk, Hver klasse i prosjektet er i stand til å lese den. På en måte etterlikner vi oppførselen til en database, med unntak av at vi hardcoding det inn i en klasse.

offentlig statisk endelig kontakt [] CONTACTS = ny kontakt [] ny kontakt ("John", "# 33b5e5", "+01 123456789", "[email protected]", "Venezia"), ny kontakt , "# ffbb33", "+01 987654321", "[email protected]", "Bologna"), ny kontakt ("Eadwine", "# ff4444", "+01 123456789", "[email protected]" , "Verona"), ny kontakt ("Teddy", "# 99cc00", "+01 987654321", "[email protected]", "Rome"), ny kontakt ("Ives", "# 33b5e5" +01 11235813 "," [email protected] "," Milan "), ny kontakt (" Alajos "," # ffbb33 "," +01 123456789 "," [email protected] "," Bologna "), ny Kontakt ("Gianluca", "# ff4444", "+01 11235813", "[email protected]", "Padova"), ny kontakt ("Fane", "# 99cc00", "+01 987654321", "fane @ example.com "," Venice "),;

Trinn 3: Definere hovedlayoutene

Oppsettet for hovedaktiviteten er enkelt, fordi listen fyller hele skjermen. Oppsettet inneholder a RelativeLayout som roten - men det kan like godt være en LinearLayout også-og a RecyclerView som sitt eneste barn.

  

Fordi det RecyclerView widgeten ordner underdelinger og ingenting mer, du må også utforme utformingen av en enkelt liste element. Vi vil ha en farget sirkel til venstre for hvert element i kontaktlisten, slik at du først må definere drawable circle.xml.

   

Du har nå alle elementene som trengs for å definere utformingen av listeposten.

      

Trinn 4: Vis dataene ved hjelp av RecyclerView

Vi har nesten kommet til slutten av første del av opplæringen. Du må fortsatt skrive RecyclerView.ViewHolder og RecyclerView.Adapter, og tilordne alt til tilhørende visning i onCreate metode for hovedaktiviteten. I dette tilfellet er det RecyclerView.ViewHolder må også kunne håndtere klikk, så du må legge til en bestemt klasse som er i stand til å gjøre det. La oss begynne å definere klassen som er ansvarlig for klikkhåndtering.

offentlig klasse RecyclerClickListener implementerer RecyclerView.OnItemTouchListener private OnItemClickListener mListener; GestureDetector mGestureDetector; offentlig grensesnitt OnItemClickListener offentlig ugyldig onItemClick (Vis visning, int posisjon);  offentlig RecyclerClickListener (Kontekst kontekst, OnItemClickListener lytter) mListener = listener; mGestureDetector = ny GestureDetector (kontekst, ny GestureDetector.SimpleOnGestureListener () @Override public boolean onSingleTapUp (MotionEvent e) return true;);  @Override public boolean onInterceptTouchEvent (RecyclerView visning, MotionEvent e) Se childView = view.findChildViewUnder (e.getX (), e.getY ()); hvis (childView! = null && mListener! = null && mGestureDetector.onTouchEvent (e)) mListener.onItemClick (childView, view.getChildPosition (childView)); returnere sant;  returner falsk;  @Override public void onTouchEvent (RecyclerView-visning, MotionEvent motionEvent) 

Det er nødvendig å spesifisere RecyclerView.Adapter, som jeg vil kalle det DataManager. Det er ansvarlig for å laste inn dataene og sette det inn i visningen av listen. Denne datahåndteringsklassen vil også inneholde definisjonen av RecyclerView.ViewHolder.

Public Class DataManager utvider RecyclerView.Adapter offentlig statisk klasse RecyclerViewHolder strekker RecyclerView.ViewHolder TextView mName, mPhone; Se mCircle; RecyclerViewHolder (Se elementView) super (itemView); mName = (TextView) itemView.findViewById (R.id.CONTACT_name); mPhone = (TextView) itemView.findViewById (R.id.CONTACT_phone); mCircle = itemView.findViewById (R.id.CONTACT_circle);  @ Overstyr offentlige RecyclerViewHolder onCreateViewHolder (ViewGroup viewGroup, int i) Vis v = LayoutInflater.from (viewGroup.getContext ()). Oppblås (R.layout.contact_item, viewGroup, false); returnere ny RecyclerViewHolder (v);  @Override public void onBindViewHolder (RecyclerViewHolder viewHolder, int i) // få det enkle elementet fra hovedmatrisefinalen Kontaktkontakt = Contact.CONTACTS [i]; // Sett verdiene viewHolder.mName.setText (contact.get (Contact.Field.NAME)); viewHolder.mPhone.setText (contact.get (Contact.Field.PHONE)); // Angi fargen på formen GradientDrawable bgShape = (GradientDrawable) viewHolder.mCircle.getBackground (); bgShape.setColor (Color.parseColor (contact.get (Contact.Field.COLOR)));  @Override public int getItemCount () returnér kontakt.CONTACTS.length; 

Til slutt legger du til følgende kode i onCreatemetode, under setContentView. Hovedaktiviteten er klar.

RecyclerView rv = (RecyclerView) findViewById (R.id.rv); // layout referanse LinearLayoutManager llm = ny LinearLayoutManager (dette); rv.setLayoutManager (LLM); rv.setHasFixedSize (true); // for å forbedre ytelsen rv.setAdapter (new DataManager ()); // dataadministratoren er tilordnet RV rv.addOnItemTouchListener (// og klikket håndteres ny RecyclerClickListener (dette, ny RecyclerClickListener.OnItemClickListener () @Override public void onItemClick (Vis visning, int posisjon) // STUB: // Klikk på elementet må håndteres));

Slik ser programmet ut hvis du bygger og kjører det.

2. Lag detaljaktiviteten

Trinn 1: Oppsettet

Den andre aktiviteten er mye enklere. Det tar IDen til kontakten valgt og henter tilleggsinformasjonen som den første aktiviteten ikke viser.

Fra et designsynspunkt er utformingen av denne aktiviteten kritisk siden den er den viktigste delen av søknaden. Men for det som gjelder XML, er det trivielt. Oppsettet er en serie av TextView forekomster plassert på en hyggelig måte, ved hjelp av RelativeLayout og LinearLayout. Slik ser layouten ut:

                    

Steg 2: Send og motta IDen via Intent Extras

Siden de to aktivitetene er knyttet sammen med en hensikt, må du sende litt informasjon som gjør det mulig for den andre aktiviteten å forstå hvilkekontakt deg om etterspørselen.

Et alternativ kan bruke posisjonsvariabelen som referanse. Plasseringen av elementet i listen tilsvarer plasseringen av elementet i arrayet, så det bør ikke være noe dårlig å bruke dette heltallet som en unik referanse.

Dette ville fungere, men hvis du tar denne tilnærmingen og, uansett grunn, datasettet er endret ved kjøring, vil referansen ikke matche kontakten du er interessert i. Dette er grunnen til at det er bedre å bruke en IDad hoc. Denne informasjonen er getId metode definert i Ta kontakt med klasse.

Rediger onItemClick håndterer av listen over elementer som vist nedenfor.

@Override public void onItemClick (Vis visning, int posisjon) Intent intention = new Intent (MainActivity.this, DetailsActivity.class); intent.putExtra (DetailsActivity.ID, Contact.CONTACTS [posisjon] .getId ()); startActivity (hensikt); 

De DetailsActivity vil motta informasjonen fra Intent ekstramateriale og konstruere det riktige objektet ved hjelp av ID som en referanse. Dette vises i følgende kodeblokk.

// Før onCreate offentlige endelige statiske String ID = "ID"; offentlig kontakt mContact;
// I onCreate, etter setContentView-metoden mContact = Contact.getItem (getIntent (). GetIntExtra (ID, 0));

Akkurat som før i onCreateViewHolder metode av RecylerView, visningene initialiseres ved hjelp av findViewById metode og befolket med setText. For eksempel, for å konfigurere navnefeltet gjør vi følgende:

mName = (TextView) findViewById (R.id.DETAILS_name); mName.setText (mContact.get (Contact.Field.NAME));

Prosessen er den samme for de andre feltene. Den andre aktiviteten er endelig klar.

3. Betydende overganger

Vi har endelig kommet til kjernen i opplæringen, og animerer de to aktivitetene ved hjelp av den nye Lollipop-metoden for overgang ved å bruke et delt element.

Trinn 1: Konfigurer prosjektet

Det første du må gjøre er å redigere temaet ditt i style.xml fil i Verdiene-V21 mappe. På denne måten aktiverer du innholdsoverganger og angir inngangen og utgangen av visningene som ikke deles mellom de to aktivitetene.

 

Vær oppmerksom på at prosjektet ditt må være målrettet mot (og dermed kompilert med) i det minste Android API 21.

Animasjonene blir ignorertpå systemer som ikke har Lollipop installert. Dessverre, på grunn av ytelsesårsaker, AppCompat biblioteket gir ikke komplett bakoverkompatibilitet for disse animasjonene.

Steg 2: Tilordne overgangsnavnet i Layout-filene

Når du har redigert din style.xml fil, du må påpeke forholdetmellom de to vanlige elementene i utsikten.

I vårt eksempel er de delte visningene feltet som inneholder navnet på kontakten, det ene av telefonnummeret og den fargede sirkelen. For hver av dem må du spesifisere en felles overgangsnavn. Av denne grunn, begynn å legge til i strings.xml ressursfilen følgende elementer:

overgang: NAVN overgang: CIRCLE overgang: TELEFON 

Deretter legger du til hvert av de tre parene i layoutfilene android: transitionName Tilordne med tilsvarende verdi. For den fargede sirkelen ser koden slik ut:

 
 

Takket være dette attributtet, vil Android vite hvilke visninger som deles mellom de to aktivitetene, og vil riktig animere overgangen. Gjenta den samme prosessen for de andre to visningene.

Trinn 3: Konfigurer intensjonen

Fra et kodende synspunkt må du legge ved en bestemt ActivityOptions bunt til hensikten. Metoden du trenger er makeSceneTransitionAnimation, som tar som parametere sammenhengen mellom søknaden og så mange delte elementer som vi trenger. I onItemClick metode av RecyclerView, rediger den tidligere definerte Intent som dette:

@Override public void onItemClick (Vis visning, int posisjon) Intent intention = new Intent (MainActivity.this, DetailsActivity.class); intent.putExtra (DetailsActivity.ID, Contact.CONTACTS [posisjon] .getId ()); ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation (// konteksten til aktiviteten MainActivity.this, // For hvert delt element legger du til denne metoden et nytt Par-element, // som inneholder referansen til visningen vi overfører * fra *, // og verdien av overgangenName attributt ny par(view.findViewById (R.id.CONTACT_circle), getString (R.string.transition_name_circle)), ny par(view.findViewById (R.id.CONTACT_name), getString (R.string.transition_name_name)), nye par(view.findViewById (R.id.CONTACT_phone), getString (R.string.transition_name_phone))); ActivityCompat.startActivity (MainActivity.this, intent, options.toBundle ()); 

For hvert delt element som skal animeres, må du legge til i makeSceneTransitionAnimation Metode en ny Par punkt. Hver Par har to verdier, den første er en referanse til visningen du overfører fra, den andre er verdi av transitionName Egenskap.

Vær forsiktig når du importerer Par klasse. Du må inkludere android.support.v4.util pakke, ikke de android.util pakke. Husk også å bruke ActivityCompat.startActivity metode i stedet for startActivity metode, fordi ellers vil du ikke kunne kjøre programmet på miljøer med API under 16.

Det er det. Du er ferdig. Det er så enkelt.

Konklusjon

I denne opplæringen lærte du hvordan du smidig og sømløst skal overgå mellom to aktiviteter som deler en eller flere vanlige elementer, noe som gir en visuelt hyggelig og meningsfull kontinuitet.

Du startet med å lage den første av de to aktivitetene, hvis rolle det er å vise listen over kontakter. Deretter fullførte du den andre aktiviteten, utformet utformingen, og implementerte en måte å passere en unik referanse mellom de to aktivitetene. Til slutt så du på hvordan makeSceneTransitionAnimation fungerer, takket være XML transitionName Egenskap.

Bonus Tips: Stilistiske detaljer

For å skape en ekte Material Design-applikasjon, som vist i de forrige skjermbildene, må du også endre fargene på temaet ditt. Rediger ditt grunntema i Verdiene-V21 mappe for å oppnå et godt resultat.