Introduction til de nye Lollipop Aktivitets Transitions
64
Del
3
Del
Dette Cyber mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av.
Hva du skal lage
Innledning
En av themost interessante aspekter ved de MaterialDesign spesifikasjoner er visualcontinuity mellom aktiviteter. Med bare noen få linjer med kode, de nye Lollipop APIer lar deg menings transitionbetween to aktiviteter, takket være sømløse og kontinuerlige animasjoner. Dette bryter de klassiske aktivitets grensene for de tidligere Android-versjoner andallows brukeren å forstå hvordan elementene gå fra ett punkt til et annet.
I denne opplæringen, vil jeg vise deg hvordan du kan oppnå dette resultatet, noe som gjør en Prøven applicationconsistent med Googles Material Design retningslinjer.
Forutsetninger
I denne opplæringen, vil jeg anta at du allerede er kjent med Android utvikling og at du bruker Android Studio som IDE. Jeg skal bruke Android hensikter mye, forutsatt en grunnleggende kunnskap om aktiviteten livssyklus, og den nye RecyclerView widget introdusert med API 21, i juni i fjor. Jeg kommer ikke til å dykke inn i detaljene i denne klassen, men hvis du er interessert, kan du finne en god forklaring på dette Tuts + tutorial.
1. Lag den første aktiviteten
Den grunnleggende structureof søknaden er grei. Det er to aktiviteter, en mainone, MainActivity.java, hvis oppgave det er å vise en liste over elementer, og en ny en, DetailActivity.java, som vil vise detaljene i itemselected i den forrige listen.
Trinn 1: RecyclerView Widget
For å vise listen over elementer, vil hovedaktiviteten bruke RecyclerView widget introdusert i Android Lollipop. Det første du trenger å gjøre er å legge til følgende linje i avhengig
delen i din project'sbuild.grade fil for å aktivere backwardcompatibility:
kompilere 'com.android.support:recyclerview-v7: + '
Trinn 2: Data Definition
For thesake av kortfattethet, vi vil ikke definere en faktisk database eller en lignende kilde ofdata for søknaden. I stedet vil vi bruke en egendefinert klasse, Kontakt. Hver itemwill har et navn, en farge, og grunnleggende kontaktinformasjon knyttet til den. Dette er hva gjennomføringen av Kontakt klassen ser slik ut:
public class Kontakt {//Feltene knyttet til personen privat endelige String mName, mPhone, mEmail, mCity, mColor; Kontakt (String navn, String farge, String telefon, String epost, String by) {mName = navn; mColor = farge; mPhone = telefon; mEmail = e-post; mCity = byen; } //Denne metoden gjør det mulig å få varen knyttet til en bestemt id, //unikt generert ved hjelp av metoden getId definert nedenfor public static Kontakt getItem (int id) {for (Kontakt element: KONTAKTER) {if (item.getId () == id) {return element; }} Returnere null; } //Siden mName og mPhone kombinert er sikkert unike, //vi ikke trenger å legge til en annen id felt public int getId () {return mName.hashCode () + mPhone.hashCode (); } Public static enum Feltet {navn, farge, telefon, epost, CITY} public String få (Field f) {switch (f) {case FARGE: returnere mColor; case TLF: returnere mPhone; case EPOST: returnere mEmail; case CITY: returnere mCity; case NAVN: default: returnere mName; }}}
Du vil ende opp med en fin beholder for den informasjonen du bryr deg om. Men vi trenger å fylle den med noen data. På toppen ofthe kontakt
klasse, legger du til følgende kodebit å fylle datasettet.
Ved å definere data som offentlig og statisk, er hver klasse i prosjektet kunne lese det . På en måte, vi etterligne oppførselen til en database med unntak av at vi er hardcoding det inn i en klasse.
Offentlige statiske endelige Kontakt [] KONTAKTER = ny kontakt [] {ny kontakt ("John", " # 33b5e5 "," 01 123 456 789 "," [email protected] "," Venice "), ny kontakt (" Valter "," # ffbb33 "," 01 987 654 321 "," [email protected] "," Bologna "), ny kontakt (" Eadwine "," # ff4444 "," 01 123 456 789 "," [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 123 456 789", "[email protected]", "Bologna"), ny kontakt ("Gianluca", "# ff4444", "01 11235813", "meg @ gian domene .lu "," Padova "), ny kontakt (" Fane "," # 99cc00 "," 01 987 654 321 "," [email protected] "," Venice "),};
Trinn 3: Definere Hoved utforminger
Thelayout av hovedaktiviteten er enkel, fordi listen vil fylle hele skjermen. Oppsettet inkluderer en RelativeLayout som rot-men det kan like gjerne være en LinearLayout altfor og en RecyclerView som sitt eneste barn
< RelativeLayout xmlns:. Android = "http://schemas.android.com/apk /res /android "android: layout_width =" match_parent "android: layout_height =" match_parent "android: bakgrunn =" # f5f5f5 "> < android.support.v7.widget.RecyclerView android: layout_width = "match_parent" android: layout_height = "match_parent" android: id = "+ id /rv" /> < /RelativeLayout >
Fordi theRecyclerView widget arrangerer delelementene og ikke noe mer, må du også designe layoutof en enkelt listeelement. Vi ønsker å ha en farget sirkel til venstre for hvert element i kontaktlisten, slik at du først må definere teikne circle.xml
< form xmlns:. Android = "http://schemas.android.com/apk /res /android "android: shape =" oval "> < solid android: color = "# 000" /> < størrelse android: width = "32dp" android: height = "32dp" /> < /form >
Du har nå alle elementene som trengs for å definere utformingen av listeelementet
< RelativeLayout. xmlns: android = "http://schemas.android.com/apk/res/android" android: layout_width = "match_parent" android: layout_height = "82dp" android: padding = "@ dimen /activity_horizontal_margin" android: bakgrunn = " ? android: selectableItemBackground "android: klikkbar =" true "android: fokuserbar =" true "android: orientering =" vertikal "> < Vis android: id = "+ id /CONTACT_circle" android: layout_width = "40dp" android: layout_height = "40dp" android: bakgrunn = "@ teikne /sirkel" android: layout_centerVertical = "true" android: layout_alignParentLeft = " true "/> < LinearLayout android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_centerVertical = "true" android: layout_toRightOf = "+ id /CONTACT_circle" android: layout_marginLeft = "@ dimen /activity_horizontal_margin" android: orientering = " vertikal "> < TextView android: id = "+ id /CONTACT_NAME" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: text = "Jonh Doe" android: textcolor = "# 000" android: Tekststørrelse = "18sp "/> < TextView android: id = "+ id /CONTACT_phone" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: text = "+ 01 123456789" android: textcolor = "# 9f9f9f" android: Tekststørrelse = " 15sp "/> < /LinearLayout > < /RelativeLayout >
Trinn 4: Vis data Bruke RecyclerView
Vi har nesten kommet til slutten av den første delen av opplæringen. Du har fortsatt å skrive RecyclerView.ViewHolder og RecyclerView.Adapter, og tildele alt til den tilknyttede visningen i onCreate metode for hovedaktiviteten. I dette tilfellet må RecyclerView.ViewHolder også være i stand til å håndtere klikk, så du må legge til en bestemt klasse i stand til å gjøre det. La oss starte definere klassen ansvarlig for klikk håndtering
public class RecyclerClickListener implementerer RecyclerView.OnItemTouchListener {private OnItemClickListener mListener.; GestureDetector mGestureDetector; felles grensesnitt OnItemClickListener {public void onItemClick (Vis visning, int posisjon); } Public RecyclerClickListener (Context kontekst, OnItemClickListener lytteren) {mListener = lytteren; mGestureDetector = new GestureDetector (kontekst, ny GestureDetector.SimpleOnGestureListener () {Override public boolean onSingleTapUp (MotionEvent e) {return true;}}); }Override Public boolean onInterceptTouchEvent (RecyclerView visning, MotionEvent e) {Vis childView = view.findChildViewUnder (e.getX (), e.getY ()); if (childView = null &! & mListener = null &! & mGestureDetector.onTouchEvent (e)) {mListener.onItemClick (childView, view.getChildPosition (childView)); return true; } Return false; }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 lasting av data og lime det inn theviews av listen. Denne data manager klassen vil også inneholde definisjonen av RecyclerView.ViewHolder
public class DataManager strekker RecyclerView.Adapter. ≪ DataManager.RecyclerViewHolder > {Public static class RecyclerViewHolder strekker RecyclerView.ViewHolder {TextView mName, mPhone; Vis mCircle; RecyclerViewHolder (Vis itemView) {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); }}Override Offentlig RecyclerViewHolder onCreateViewHolder (ViewGroup viewGroup, int i) {Vis v = LayoutInflater.from (viewGroup.getContext ()) blåse (R.layout.contact_item, viewGroup, false).; returnere ny RecyclerViewHolder (v); }Override Public void onBindViewHolder (RecyclerViewHolder viewHolder, int i) {//få enkelt element fra hoved rekke endelige Kontakt kontakt = Contact.CONTACTS [i]; //Sett verdiene viewHolder.mName.setText (contact.get (Contact.Field.NAME)); viewHolder.mPhone.setText (contact.get (Contact.Field.PHONE)); //Sett farge på formen GradientDrawable bgShape = (GradientDrawable) viewHolder.mCircle.getBackground (); bgShape.setColor (Color.parseColor (contact.get (Contact.Field.COLOR))); }Override Public int getItemCount () {return Contact.CONTACTS.length; }}
Til slutt legger du til følgende kode i den onCreate
metode, under setContentView. Hovedaktiviteten er klar
RecyclerView rv = (RecyclerView) findViewById (R.id.rv.); //Layout referenceLinearLayoutManager LLM = new LinearLayoutManager (denne); rv.setLayoutManager (LLM); rv.setHasFixedSize (true); //For å forbedre performancerv.setAdapter (ny DataManager ()); //Data manager er assigner til RVrv.addOnItemTouchListener (//og klikk håndteres ny RecyclerClickListener (dette, ny RecyclerClickListener.OnItemClickListener () {Override public void onItemClick (Vis visning, int posisjon) {//STUB: //Klikket på elementet skal håndteres}}));.
Dette er hva programmet ser ut som om du bygge og drive det
2. Createthe Detaljer aktivitet
Trinn 1: Oppsett
secondactivity er mye enklere. Det tar ID-en til kontakt valgt og retrievesthe ytterligere informasjon som den første aktiviteten ikke viser.
Fra et designsynspunkt, er utformingen av denne aktiviteten kritisk siden det er den viktigste delen av søknaden . Men for hva gjelder XML, det er trivielt. Oppsettet er en serie av TextView tilfeller plassert på en hyggelig måte, ved hjelp RelativeLayout og LinearLayout. Dette er hva oppsettet ser ut: Search < LinearLayout xmlns: Android = "http://schemas.android.com/apk/res/android~~number=plural" xmlns: verktøy = "http://schemas.android.com/verktøy "android: layout_width =" match_parent "android: layout_height =" match_parent "android: orientering =" vertikal "> < Imageview android: layout_width = "match_parent" android: layout_height = "200dp" android: scaleType = "centerCrop" android: src = "@ Mipmap /material_wallpaper" /> < RelativeLayout android: layout_width = "match_parent" android: layout_height = "82dp" android: padding = "@ dimen /activity_vertical_margin" > < Vis android: id = "+ id /DETAILS_circle" android: layout_width = "48dp" android: layout_height = "48dp" android: bakgrunn = "@ teikne /sirkel" android: layout_centerVertical = "true" android: layout_alignParentLeft = " true "/> < TextView android: id = "+ id /DETAILS_name" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: text = "Jonh Doe" android: layout_toRightOf = "+ id /DETAILS_circle" android: layout_marginLeft = "@ dimen /activity_horizontal_margin" android: layout_centerVertical = "true" android: textcolor = "# 000" android: Tekststørrelse = "25sp" /> < /RelativeLayout > < LinearLayout android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_centerVertical = "true" android: padding = "@ dimen /activity_horizontal_margin" android: orientering = "vertikal" > < RelativeLayout android: layout_width = "match_parent" android: layout_height = "wrap_content" > < TextView android: id = "+ id /DETAILS_phone_label" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: text = "Telefon:" android: textcolor = "# 000" android: Tekststørrelse = "20sp "/> < TextView android: id = "+ id /DETAILS_phone" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_toRightOf = "+ id /DETAILS_phone_label" android: layout_marginLeft = "@ dimen /activity_horizontal_margin" android : text = "+ 01 123456789" android: textcolor = "# 9f9f9f" android: Tekststørrelse = "20sp" /> < /RelativeLayout > < RelativeLayout android: layout_width = "match_parent" android: layout_height = "wrap_content" android: layout_marginTop = "@ dimen /activity_vertical_margin" > < TextView android: id = "+ id /DETAILS_email_label" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: text = "E-post:" android: textcolor = "# 000" android: Tekststørrelse = "20sp "/> < TextView android: id = "+ id /DETAILS_email" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_toRightOf = "+ id /DETAILS_email_label" android: layout_marginLeft = "@ dimen /activity_horizontal_margin" android : text = "[email protected]" android: textcolor = "# 9f9f9f" android: Tekststørrelse = "20sp" /> < /RelativeLayout > < RelativeLayout android: layout_width = "match_parent" android: layout_height = "wrap_content" android: layout_marginTop = "@ dimen /activity_vertical_margin" > < TextView android: id = "+ id /DETAILS_city_label" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: text = "By:" android: textcolor = "# 000" android: Tekststørrelse = "20sp "/> < TextView android: id = "+ id /DETAILS_city" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_toRightOf = "+ id /DETAILS_city_label" android: layout_marginLeft = "@ dimen /activity_horizontal_margin" android : text = "Rome" android: textcolor = "# 9f9f9f" android: Tekststørrelse = "20sp" /> < /RelativeLayout > < /LinearLayout > < /LinearLayout >
Trinn 2: Send og Motta ID via Intent Extras
Siden thetwo aktiviteter er forbundet med en hensikt, må du sende noen stykke informasjon som gjør at andre aktiviteten å forstå som Ett alternativ kanskje bruke posisjonen variabel som referanse. Posisjonen til elementet inthe listen tilsvarer posisjonen til elementet i gruppen så thereshould være noe dårlig i å bruke denne heltall som en unik referanse. Dette ville fungere, men hvis du tar denne tilnærmingen, og for Uansett grunn, er datasettet endres under kjøring, vil referanse ikke matche den kontakten du er interessert i. Dette er grunnen til at det er betterto bruke en ID Rediger onItemClick handler på listen over elementer som vist nedenfor. DetailsActivity vil motta informasjon fra intensjonen statister og bygge den riktige objektet med ID som referanse. Dette er vist i følgende kode blokken Akkurat som før i onCreateViewHolder metoden i RecylerView, er utsikten initializedusing den findViewById metode og befolket hjelp setText. For eksempel vil konfigurere navnefeltet vi gjør følgende: theprocess er den samme for de andre feltene. Den secondactivity er endelig klar. Vihar endelig kommet til kjernen av opplæringen, animere de to aktivitetene ved hjelp av den nye Lollipop metode for overgangen ved hjelp ashared element firstthing du trenger å gjøre er å redigere ditt tema i style.xml filen i verdier-V21-mappen. På denne måten gjør at du innholds overganger og setthe inngang og utgang av visningene som ikke deles mellom de to aktivitetene Please Merk at yourproject må være rettet mot (og dermed være kompilert med) minst Android API 21. Animasjonene vil bli ignorert på systemer som ikke haveLollipop installert. Dessverre, på grunn av ytelsesgrunner, de AppCompat librarydoes ikke gi fullstendig bakoverkompatibilitet for disse animasjonene Når du 've redigert style.xml fil, haveto du påpeke forholdet mellom de to vanligste elementene i theviews. I vårt eksempel, de delte utsikten er felt som inneholder navnet ofthe kontakt, den ene av telefonen nummer, og den fargede sirkelen. Foreach av dem, må du oppgi en felles overgang navn. Av denne grunn, begynne å legge i strings.xml resourcefile følgende elementer: Så, for hver av de tre parene, i layoutfiler legge til android: transitionNameattribute med tilsvarende verdi. For den fargede sirkelen, ser koden ut: Takk tothis attributt, Android vil vite hvilke synspunkter deles mellom de twoactivities og vil korrekt animere overgangen. Gjenta det samme processfor de to andre visningene Froma koding synspunkt, må du legge ved en bestemt ActivityOptions pakke til hensikt. Metoden du trenger er makeSceneTransitionAnimation, whichtakes som parametre sammenheng med søknaden og så mange delte elementsas vi trenger. I onItemClick metoden ofthe RecyclerView, redigere tidligere definert Intent som dette: For hver delte elementet som skal animeres, må du legge til makeSceneTransitionAnimation metoden et par nye element. Hvert par har to verdier, den første er en referanse til visningen du er overgangen fra, den andre er verdien av transitionName attributtet. Vær forsiktig når du importerer Pair klassen. Du må inkludere android.support.v4.util pakken, ikke anbefale den android.util pakken. Husk også å bruke ActivityCompat.startActivity metoden i stedet for startActivity metoden, fordi ellers vil du ikke være i stand til å kjøre applicationon miljøer med API under 16. Det var det. Du er ferdig. Det er assimple som det. I thistutorial du lærte å vakkert og sømløst overgang mellom twoactivities som deler en eller flere felles elementer, noe som åpner for en visuallypleasant og meningsfull kontinuitet. tocreate en sann Material Design jakt program, som vist i de foregående skjermbilder, du må også changethe fargene i temaet. Redigere din base tema i verdier-V21 mappe toachieve et fint resultat
kontakte deg bedt detaljene.
ad hoc. Denne informasjonen er getId metoden definert i kontakt klassen.
Override Public void onItemClick (Vis visning, int posisjon) {Intent hensikt = ny Intent (MainActivity.this, DetailsActivity.class); intent.putExtra (DetailsActivity.ID, Contact.CONTACTS [posisjon] .getId ()); startActivity (hensikt);}
//Før onCreatepublic endelige statiske String ID = "ID."; Offentlig Kontakt mContact;. //I onCreate, etter setContentView methodmContact = Contact.getItem (getIntent () getIntExtra (ID, 0));
mName = (TextView) findViewById (R.id.DETAILS_name); mName.setText (mContact.get (Contact.Field.NAME));
3. Meningsfulle overganger
Trinn 1:. Konfigurer Prosjekt
. ≪ style name = "AppTheme" forelder = "AppTheme.Base" > < /style > < style name = "AppTheme.Base" forelder = "android: Theme.Material.Light" > < element name = "android: windowContentTransitions" > ekte < /element > < element name = "android: windowEnterTransition" >android: overgang /slide_bottom < /element > < element name = "android: windowExitTransition" >android: overgang /slide_bottom < /element > < element name = "android: windowAllowEnterTransitionOverlap" > ekte < /element > < element name = "android: windowAllowReturnTransitionOverlap" > ekte < /element > < element name = "android: windowSharedElementEnterTransition" >android: overgang /flytte < /element > < element name="android:windowSharedElementExitTransition">@android:transition/move</item></style>
Trinn 2:. Tilordne Transition Navn i Layout Files
< string name = "transition_name_name" > overgang: NAVN < /string > < string name = "transition_name_circle" > overgang: CIRCLE < /string > < string name = "transition_name_phone" > overgang: Telefon < /string >
< - I enkeltelement layout: elementet vi er overgangen * fra * - > < Vis android: id = "+ id /CONTACT_circle" android : transitionName = "@ streng /transition_name_circle" android: layout_width = "40dp" android: layout_height = "40dp" android: bakgrunn = "@ teikne /sirkel" android: layout_centerVertical = "true" android: layout_alignParentLeft = "true" /> ! < - I detalj aktivitet: elementet vi er overgangen * til * - > < Vis android: id = "+ id /DETAILS_circle" android: transitionName = "@ streng /transition_name_circle" android: layout_width = "48dp "android: layout_height =" 48dp "android: bakgrunn =" @ teikne /sirkel "android: layout_centerVertical =" true "android: layout_alignParentLeft =" true "/>
Trinn 3:. Konfigurer Intent
Override public void onItemClick (Vis visning, int posisjon) {Intent hensikt = new Intent (MainActivity.this, DetailsActivity.class); intent.putExtra (DetailsActivity.ID, Contact.CONTACTS [posisjon] .getId ()); ActivityOptionsCompat alternativer = ActivityOptionsCompat.makeSceneTransitionAnimation (//sammenheng med aktivitets MainActivity.this, //For hver delte element, legge til denne metoden et par nye element, //som inneholder henvisningen av utsikten vi er overgangen * fra *, //og verdien av transitionName tilskriver nye Pair < View, String > (view.findViewById (R.id.CONTACT_circle), getString (R.string.transition_name_circle)), ny Pair < View, String > (view.findViewById ( R.id.CONTACT_name), getString (R.string.transition_name_name)), ny Pair < View, String > (view.findViewById (R.id.CONTACT_phone), getString (R.string.transition_name_phone))); ActivityCompat.startActivity (MainActivity.this, forsett, options.toBundle ());}
Konklusjon
< p> Du startet med å lage den første av thetwo aktiviteter, hvis rolle det er å vise listen over kontakter. Deretter completedthe andre aktivitet, designe sin layout, og implementere en måte å passere en uniquereference mellom de to aktivitetene. Til slutt, du så på den måten som makeSceneTransitionAnimation fungerer, takket være XML transitionName attributtet
BonusTip. Stylistic Detaljer
. ≪ style name = "AppTheme" forelder = "AppTheme.Base" > < element name = "android: windowTitleSize" > 0DP < /element > < element name = "android: colorPrimary" > @ farge /colorPrimary < /element > < element name = "android: colorPrimaryDark" > @ farge /colorPrimaryDark < /element > < element name = "android: colorAccent" > @ farge /colorAccent < /element > < element name = "android: textColorPrimary" > # fff < /element > < element name = "android: textcolor" > # 727272 < /element > < element name = "android: navigationBarColor" > # 303F9F < /element > < /style >