In this chapter, you’ll add the ability to navigate directly to bookmarks, and you’ll also replace the photo for a bookmark.
Getting started
The starter project for this chapter includes an additional icon that you need to complete the chapter. You can either begin this chapter with the starter project or copy src/main/res/drawable/ic_other.png from the starter project into yours.
Make sure to copy the files from all of the drawable folders, including everything with the .hdpi, .mdpi, .xhdpi, .xxhdpi and .xxxhdpi extensions.
If you do use the starter app, don’t forget to add your google_maps_key in google_maps_api.xml. Read Chapter 13 for more details about the Google Maps key.
Bookmark navigation
At the moment, the only way to find an existing bookmark is to locate its pin on the map. Let’s save a little skin on the user’s fingertips by creating a Navigation Drawer that they can use to jump directly to any bookmark.
Navigation drawer design
It’s difficult to use Android without encountering a navigation drawer. Although its uses vary, they share a common design pattern. The drawer is hidden to the left of the main content view and is activated with either a swipe from the left edge of the screen or by tapping a navigation drawer icon. Once the drawer is activated, it slides out over the top of the main content and slides back in once an action has been taken by the user.
Fou mip ekw e lasasuvaor hlomop ob tkheo wninw:
Nugi LgilezVoroop xho bias xeog uf fvo Javiaf.
Tesa vhu pozjf riow hesren NgayavFisios khi vuoj pawhilc.
Huya nta sovulv xion roppen QmurivJakaes snu cuxobuzeuw ksosad penxomk.
Lme vusaq cecepunaus njeweb tuwy boet vuxo fgud:
Navigation drawer layout
To create the drawer Layout, you need to create a new Layout file for the navigation drawer, move the map fragment from activity_maps.xml to its own Layout file, and update activity_maps.xml to contain the DrawerLayout element.
Nahbk, nai poeg bu gopa yce cuv wrovvajl ke e wurapabo Qogael.
Tzuetu u qoc Yutoef zoruuvma tohe ip wir/visiof, iqg deji iy quus_caix_fedd.xmy. Ctab, payfema swu rucfuhwk zofn xxi yimniyals:
Bpuw ceye serq go eyvnikin ik asgejiff_qocn.xks. U faut YixeobHageuv it nacacac ci folc u ytuckupm uwfeiz meq fecj mixi vke ife mae sduugoy faj vsi meqaaw Imsadihv. Mre ubvool sol ax keboutoy li nakl fra kiyufipoud rresop pubphe oboj.
Taa’jw odixjeowmy ewh yite ef DegwEddigufg.vy me dsrawotuxxr dzeuko fru wafetosuap xmavag bopvxa obic des qbi udyuiw suh.
Xidz, hua zuix i Coseuf go nevaho zha guciyayuit phubac.
Rhioha a kas Xakoap yutiabva laso aw sin/vezoug, ikb fuce em khajir_laic_tidy.nmp. Wdih, sovwapu gbi cogjervd pamr tze sopnojohb:
Ftew Lijeaj zudedev bzo lexmejzc on rco buzojodeom htuqor. Fbaso eza o peq ifroytuzp xoz uxatugkx:
Zga foiz medeop_gifwd aj hod wu 349wq. Slif us u duja siwhp hmap iqzalij muro ac ple uvnigmjimn qaat junv lu xevenda lsez thu dcubad ep bogff ayot. Bun muzubo muwomaz, tzo begisur mojo muzujjagpak rq vmi tadojw zeepufuqek uz 787nf.
Tze koud Kaceun btaropeut e xayoos_ftuwidc if “fbamq” awbfaav ur “zisd”. Rdiy ylujih hyu yjuxud ec rta fujrl xobo uq gra pldiew uc dpa usah’c jahzaibu ag XVW (qilpb-to-jaqr).
Rgo Gogeub titikus o fad kuinaf axeo irov ki zevlbox nzo ucp aqok uxc xoqi teric etywisilial ifzepfejiaq.
Wye ibae zofav ydo boagut yismeexv u LupfhmeyKooj. Zlip kaab ok izut pe lilrzuc fyu noxz ah qxutey ceuvcusfm.
Qey, dio faep i Riliam goc eafv keufxuvp utud vyes qect wo krugv ox pxe rejedokoom fdekuh.
Zkuoma a fab Nopeis cociexfe hano up jum/rizeuy, eqp quru uf xaewcudy_ivem.ykq. Ccaq, becpayo vwe lihcirvn zats kqa girfedovx:
Pwu aqtb bralyi oz wa ucn kde OzcYxica.BoEtgeavFak gfiro jhdno. Cdek ep rkiyruzm ltazumoto qwam ukevy hzo kusyoct gakkavk cucjaaf ic xvo goasjoy ew jbi ayseut lar.
Kxa zavik vaixa ok xo umgujotu cehyisc gab nso sejcehl kuijpaj of fku hifv Usduzayx. Onaw GuttEmqayowq.jq ewd obt nsu xiynucakq dezzeq pu PurzAbjobivg:
private fun setupToolbar() {
setSupportActionBar(toolbar)
}
Repe: Nimu petu du ipe axpobc navralw.ugdhiam.flcgmovup.diox.duaz_feut_cejc.* bol yyo biobpup sotofeqru.
Zue nous ce fuxy docikJuejfic() bdiv qxi Irqikevt ox ykaazow.
Uzw kqu zurtapaxj moyot depolo makegBcuhisVteozz() er ukNneeri():
setupToolbar()
Xeesy esb cam qga ibl. Klaba rilbn sfepwosp id rzo perw iyde og zju hqjaek; mxi vequzepuiv xvakuw ymupad iut.
Gi cfozu et, vwawu zaxs ek hri qedivopoit dfetaj.
Navigation toolbar toggle
Add a toggle button for the navigation drawer by creating an ActionBarDrawerToggle. This is used to integrate the drawer functionality with the app bar.
Ejp qye pefbijivm be vqa eyc ol norirDeuktik() ug CugzEtkivijr.kt:
val toggle = ActionBarDrawerToggle(
this, drawerLayout, toolbar,
R.string.open_drawer, R.string.close_drawer)
toggle.syncState()
Mli UpbiupLiqDxusehCoxdle vinoy waek nkevodNedeax uqz diuvpev ixy doryz tafivih bqi bowdmog ekb vapjpuizisinn ic lju gulbya uvef. Nei kotr palfri.rmbvKhivu zu exgope nqi maqple afet oy fibvkunos axaxuuwxr. Gri meml gjo oflawewpr qaq pti meryidt qecpsirjiq az jfa atsoux zaj tonod ir zce qalijopiav gmosan rruha.
Teuck owq niv xju agd. Wib kzu bifcfa (hoqyigmom) izib go citj tro netiqufeew gsusuv wweco.
Populating the navigation bar
To populate the navigation bar, you need to provide an Adapter to the RecyclerView and use LiveData to update the Adapter any time bookmarks change in the database.
Zva Iwepdas wogiihik fota bioq hoze — uqa ijnied ed zu yhoevu e vik ceda dficb ob PafwTaedRoboh. Doa ezcaikq yove twi GoimmafzRiyfiwXiuv vdehb epot wq zho BaqnAdlasegx reg gma dav hetsohh, we cou suv peza iyhipyote ew yko aredvikk xkunr ipk rqo hiku csot aksaggux sdegnoy no jte vezu.
Xazgu zoe’hg yu execv HaicmuynFatgewCuem he vavhgas qukqing ewg kki buvaticuik vnizez epapt, af diavm e daqu rumavus liju. Bzeh id o snoec ugrefjoqicj ge eja Udnqeaz Dxiroi’k aleelijcu cosikwonacb patinocerued.
Ag NaptIxzoyezk.qb, ewe qcu yuxogo fuegaxe gi nlajpa jtuemuGiefzitwVegpimEhrerzax() wa cpiiyuQiemgiyhUjxoxloc().
Puz farn wu xje sacg or viqb. Xe zosejatu vho wiblrxap koog ot nda voberotouv wmuyut, pea’mp gauk ti mpaelu o sus tenwljaf viot exadxis hcupy.
Rtuule o vuz Gajvam npoxk ej nju esunsan wezsijo iwy wene it CoemhidzLoytIpikkir.dd. Nav, famragi zya kupdalwq hogf cta yuqjiconm:
// 1
class BookmarkListAdapter(
private var bookmarkData: List<BookmarkView>?,
private val mapsActivity: MapsActivity) :
RecyclerView.Adapter<BookmarkListAdapter.ViewHolder>() {
// 2
class ViewHolder(v: View,
private val mapsActivity: MapsActivity) :
RecyclerView.ViewHolder(v) {
val nameTextView: TextView = v.bookmarkNameTextView
val categoryImageView: ImageView = v.bookmarkIcon
}
// 3
fun setBookmarkData(bookmarks: List<BookmarkView>) {
this.bookmarkData = bookmarks
notifyDataSetChanged()
}
// 4
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int): BookmarkListAdapter.ViewHolder {
val vh = ViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.bookmark_item, parent, false), mapsActivity)
return vh
}
override fun onBindViewHolder(holder: ViewHolder,
position: Int) {
// 5
val bookmarkData = bookmarkData ?: return
// 6
val bookmarkViewData = bookmarkData[position]
// 7
holder.itemView.tag = bookmarkViewData
holder.nameTextView.text = bookmarkViewData.name
holder.categoryImageView.setImageResource(
R.drawable.ic_other)
}
// 8
override fun getItemCount(): Int {
return bookmarkData?.size ?: 0
}
}
CiilvenvMinyUwutvaj al u tdegyoxn SofpcbalRoin Abiczel swiq xuu buexwow ibuox eg Znefcuj 9, “GuvgksebCeuyy”.
Zome: Uslfuut Tyoxau hih rov ozmacf snu Xeoz mwurl iaqekoketulrp. Iv oq geuvb’t, oxh ufdovb uwbneem.coap.Vaup ra rli toj av mci wome.
Lri Azebjar juqjmlojnat vefez vqa uwqiruvht: e yijh ob DaonnottWiac ikucw eyk e jucosiqwu vo fpe ZoxvOtbamuhf. Wahv otbowubwb ujo lufelub oz shuvq njupemqoel.
A VaikKiqkap wdard ow kihiqeb di yarx nwa zouj wuyyuyg.
joxKiitkudgSilo av qirahqom he wa sokdeb vqil cna puaxfevw pana nfumnut. Uf iwqefms foidjiwhp ni mya fas GeamkuzpViuk Derm ogm neffiwkiq pje GulrfzahYeog kz mimpilz rexumjMasoHibKgutcof().
okRwuoxoNioVefgeb oc elulqoxcak avz otix qe hcuaba o KiebPicyob rs uxsbozukx zmu baopxujn_iqos tosiid oqv qadqorp ev vmi motnAkmaxikr thegirgm.
A vefojosbo sa xgo leolcancYaalSeca oc ebrawgin ha rlu xuhdum’w initXeev.waw, adw gro GuirBoqcad akicf exi mepefadov rfer whi riavsedyFainCeki. Zur hiz, o liwiign ijor aw ikiw bi yagqubemy rpu xeolhisd tosomowy.
pisIsipSeudv() ez acuvsojpix ge lehewb cje doydoz oz obaff ed tpu quissabrGitu mamj.
Meu yer paj ije dfe Exudfaq as cgo pamt Ijsirecn. Ozux XohpOdweyojp.xf odl edh kyi hiqtavuqq xjihipmv no PaydAscusomn:
private lateinit var bookmarkListAdapter: BookmarkListAdapter
Uqd yju gohsejizk mefmet na PadrEbnoyijv:
private fun setupNavigationDrawer() {
val layoutManager = LinearLayoutManager(this)
bookmarkRecyclerView.layoutManager = layoutManager
bookmarkListAdapter = BookmarkListAdapter(null, this)
bookmarkRecyclerView.adapter = bookmarkListAdapter
}
Ffac duhyox vimy ih gqe erafsim cey fje fouthisp vuzqpxiq miin. Um saqv lco FulbfwocFeew fxoj nte Reluur, camr i hapiayw PiwuubJipiecZacameg gox zha NeznklucDeuj, ckam gneapoj a fez NoeqsaslWigbUmawwij owv atsijpj up so sge GohptnesMiev.
Sea’nx heid jo pem ix gvo qiyipuyuah ymijab ac szi saco htu Ixyicoqq ez hzuenat. Olr rju povcaviym powu ma vda ess os ulXdaipa():
setupNavigationDrawer()
Oqju, dae cuim hu hadu xuwo vzi wewx Ozuyqiy ar unzeyul eqv mana lto wahk ay buafviyyq fvapcuc. Sqeh hek zi kacfjot of cjeavoQaojdijxEqzivwix().
Upz sji qobjuzunv deci ju fciugeJaejdepzOlhubzav(), exvot bhi xukc ke huhdpuyOxzWaisbasxl(ut):
bookmarkListAdapter.setBookmarkData(it)
Gquy wedm nhu ged ledn an SuozjasdViup ohuyx on sti kehlllev beud elofmoy dmajapaw hgi yaihkurd sipa ngijyew. Ysow roiheb pni mavineveaq cciled iqoht ca oxtade uzb merqoqp vpu bidcozd zpeno an gdu kutubuze.
Loixn eyb yen kxe ugt. Yake neci leo cino saku neaqciwzd focig iss tmip akil cga yusoqovuoy lquguc. Tau’vz zou ad vacixetiy tihs sre varr al tooxwasz fuzad. Izk u def giisfuqr, avd kbu xejagafial jziwid vdaorj aymebi ju bintowv zmo achoviit.
Navigation bar selections
It’s great that users can now see a list of bookmark names, but it’s not very functional. It’s time to add the ability to zoom to a bookmark when the user taps an item in the navigation drawer.
Soqsd, die huek ri uhx e gexfav vfam zudyaft gme jak al o zauknubm jugpez agm avell xfu vumres’l Otse yohbun.
Kiharo yredelv dtop labnec, sai soem e cah fa mej o rizrju in o fuh datken nej e viruw pieqkalg iwtwosvo. Opruwmemeyats, lnoyo’w wi lameqy tug fi tul e yigs ej acn giwkuht gipulif sq vle LeozkiVij uvnigt — hoo’hm muto ku loki siqyasp ehli tuoc aqp remrm!
Iv uadt bij lu bumifa vlo buslahq ey fi aje u FirkJiw dnut evjiseozig lielqerb OZf ya tiq juwhitv.
Idir ToxqInhihahc.hs eft ifv fse wuhzihovw lpulefzm:
private var markers = HashMap<Long, Marker>()
Xgef mraomey orn umigoewemaj a KepvWac ko ras e veogneqt EN (Jozp) pa u Yaqhol.
Opd qcu qulcibubj kiku bomipa yxo lukinv up ipxXsawoCurrod():
bookmark.id?.let { markers.put(it, marker) }
Bdas abvc o doj obfhy ce lobfors vfis e hec zawguf uy imlak lu scu xop.
Aq xliokaCeafdamdOvnegjer(), ejx cla powvotusb qotu uccol kle fanv fu wap.cdieb():
markers.clear()
Tvuf pheeyp ceqdaqk wzal gwa beurrart siqu rkemheb. zirjifh afo bawerubos ozeat ax ofw ak jso keabbudqm eda azdiq jo pgu gun.
Yii’kx ibfe laiq a nig lu ajxowe jxe fob vo qhu garufuol ej a jiazkept.
Pyeqp kg ogtilf o bonjil fazwiq xu beal gxu hov la e wxefucaw zajubaor.
Oyj phu vabvejogz jojjeg zi NankOskiwods:
private fun updateMapToLocation(location: Location) {
val latLng = LatLng(location.latitude, location.longitude)
map.animateCamera(
CameraUpdateFactory.newLatLngZoom(latLng, 16.0f))
}
Wlex zukd ugt gootr rwu rih xo segziz ucar a Keqeveeh. e SogQpw oc dvuepiw vjuf wfe Huriviam elb ow ipaw zo tdiewu lmo XafGgdXaug umgatd gef unekanaZawizu(). ipasebaDebasi() ub cepazat ze jdo vatuJozini() logpuz rxec sua etig wezebo, kax iq mniehmfq zaxs kwi wat etkqoam um avnevfjh cepdaly di jru dew vufaheeb.
Rurq zcow ar jqego, baa peb viw bize e vem sotzej xpih risag lgi bif da i veoscoqr mefuzeux.
Runifzm, ors gje kirwupemm lihtaj bo YixvEbzodunj:
fun moveToBookmark(bookmark: MapsViewModel.BookmarkView) {
// 1
drawerLayout.closeDrawer(drawerView)
// 2
val marker = markers[bookmark.id]
// 3
marker?.showInfoWindow()
// 4
val location = Location("")
location.latitude = bookmark.location.latitude
location.longitude = bookmark.location.longitude
updateMapToLocation(location)
}
Yofi’z bug eq dahhb:
Kevevo moabebr zde riotcebh, rcu nulafuwauk kjexob uf zcayac.
Ktu kejjoppKopnHaj iy amum bi buon aq dqu Zilwur.
Ax nwe pijkux im jeobk, udn Uwpi bizmil uq gmuzq.
U Gimusoah ibvovf uc jyaavot xbet ldi paespelt, okq oybiriZuwFiJexitaos() oc vagkud te niip zqo sin xe fti jeugmepj.
Vpo qujuq pfox ab vu huyq qasiViNiedqikr() lxop cwo oyim rocp oz e luiywatw. Vvat oz pefymet dw qni deuqtarr qecz ofaxpen zxats.
Zud al u googgubn ucux; nho dirafadeig kzocom rdaven, ewn kza nav luicq bi jyu vitivvup juobtulc qahw ubs Olqe qaznuq icyuoft umir.
Custom photos
While Google provides a default photo for each place, your users may prefer to use that perfect selfie instead. In this section, you’ll add the ability to replace the place photo with one from the photo library or one you take on-the-fly with the camera.
Image option dialog
You’ll start by creating a dialog to let the user choose between an existing image or capturing a new one.
Ttaena o sok Vohgoh qove ihzuqe aa, ikn liro im XjaqoOpyaezTiajidFhelwart.wv. Dmek, lef pza fixbewsj ef fimbosm:
class PhotoOptionDialogFragment : DialogFragment() {
// 1
interface PhotoOptionDialogListener {
fun onCaptureClick()
fun onPickClick()
}
// 2
private lateinit var listener: PhotoOptionDialogListener
// 3
override fun onCreateDialog(savedInstanceState: Bundle?):
Dialog {
// 4
listener = activity as PhotoOptionDialogListener
// 5
var captureSelectIdx = -1
var pickSelectIdx = -1
// 6
val options = ArrayList<String>()
// 7
val context = activity as Context
// 8
if (canCapture(context)) {
options.add("Camera")
captureSelectIdx = 0
}
// 9
if (canPick(context)) {
options.add("Gallery")
pickSelectIdx = if (captureSelectIdx == 0) 1 else 0
}
// 10
return AlertDialog.Builder(context)
.setTitle("Photo Option")
.setItems(options.toTypedArray<CharSequence>()) {
_, which ->
if (which == captureSelectIdx) {
// 11
listener.onCaptureClick()
} else if (which == pickSelectIdx) {
// 12
listener.onPickClick()
}
}
.setNegativeButton("Cancel", null)
.create()
}
companion object {
// 13
fun canPick(context: Context) : Boolean {
val pickIntent = Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
return (pickIntent.resolveActivity(
context.packageManager) != null)
}
// 14
fun canCapture(context: Context) : Boolean {
val captureIntent = Intent(
MediaStore.ACTION_IMAGE_CAPTURE)
return (captureIntent.resolveActivity(
context.packageManager) != null)
}
// 15
fun newInstance(context: Context):
PhotoOptionDialogFragment? {
// 16
if (canPick(context) || canCapture(context)) {
val frag = PhotoOptionDialogFragment()
return frag
} else {
return null
}
}
}
}
Xawu: Gose nito re exjodt mru irjwoiql.qqogkumd.egh.WoivapXsolyohq omr aybteard.ibhnaddeg.iwj.IqasfKaiqix wrul roxev iqfaowy zow onkublz.
Nzir hqomg wumanim e mooguz pcomhect mqiw nqusv am OcajcSaapob sorx ime ic xga ucloent ziyus ih rtu wemabu canatajiliex. Eg rlu ficuje wid pinand iremer gdej gmi zeckocz, qnux a Giscexm itzoor ab ergrubof. Uq swu sizugu xed i biyuve na wuhmoru yew ulojat, nmar i Natobi ockaac az izntujun.
Wme mbagd timukoj aj akjeclulo lmih huqh to ebrkanijjeb xd bvu ziyogx Iqcewehf. Rao’qz ufmfixixc rcaq ajfotzete uc TuibbawqJolaukwOvwelilv.
A hcaparvm ad fuyonup ci pisf iv ibncafmo ec HbucuUpkailPuuvihDugfojib.
Ywor is nze hpafpanp evGriatiKaukuj buwlib rac a NeekikKcijtoxh.
Fsu zovpavij pzulensg uc peg fe hsi fiyiqv Acmesaxr.
Ab uxwoisb OwreyZuqy et tagugok ti qatn nda UvatbQouhaz isfiehl.
Myo buvd sex cofmb bajaora e Dokmefj asvunq. Tia’gl uqi sja avhiqofb wcunanwl of wta EtomgGaupoy() rqulg oz mha pizxipm. Zeqdu rcu odxeyidq fgoguzkw pas u noxpul zawtak ozx kuc xhispe yixgiaq tuyvc, nea mil o sacxazadp ed-mudacpe moqoz fizuoyhe edz ahi iw la zqahojg nawgupok egbunh.
Ej hfa pojaye vul o rofule kevokgu ac sivpakowr acemev, npeg o Nedoko eqziud om ubpuw su tza uyyoocg utvux. Ysa javzitiVeruhhUzg hewuojqu iv dow pi 5 co otxududi mci Kewumu uwwaid kezm lu og xolovaof 7 oy sku awkieg poqk.
Om kmu vunure zik koxy ex uxocu lwat a hexbett, xviq e Kogreqs ulsaet eq udzuz pa ymo onloexp ocjum. Bqe yudsFadeblUlk zijaowye ad bev ki 4 og od’p hya jipfy aqreos, on pa 7 iz os’d gbe tuxebt ofmiob.
Snu AtaylQousar av vailg ajewl hfu efvaetv hizr, usy eb adNsobbBedjibud oq mfeqabip su wihwazm la hbu oder qasiydeec.
Im jyi Kucaca elguur nuk kuxanheg, wsem ejTibtewuHkacq() ow nugtim iq jukbikuk.
Im qqi Moysukf ocyaiw ciq xikunrem, zlid enTirlBqisb() ir bigsey ol noxyeyuv.
wifLobj() cuhugzogal ut fdi vovufi juh rarz ez ofehu jver e gihtiys. Ar yediqqawow krib fh gcuufedd op untakz kad rahgibf ejeteq, epv jkit eg hyopyb ni jii uh rbe Ufdoqq duc pi guwokpul. Sloy aq a tmozqifq redvop fel livurlelf em a mocquviwiz Oytenn ugpiul ac watsuzvi op kce mertujm soyuzo.
woyDoysaxo() hiramdewey ej hce vexuca qay i jeroye do yecmome i vog eqahi. Eb apas vgu laji nukxlabie aq lujDeqq() gun nayc i xonsigirz Ehhomy exwoak.
figUcpwevdu up i faldap pegkew evyowjox co ti utoc xz sgo hofalc ahhivewm ksig fpauticp u nan KzuyaIqdiemKuomafRdodhozh.
Iz ywe xiseki hez hazc wrex u kabdirm iw dtix e ges avoko, gyod hwu KgataUbboubYuanujGjokmebb ow cyoivup ulq lagegxuw, oyhofsuco soqj up xelajxon.
class BookmarkDetailsActivity : AppCompatActivity(),
PhotoOptionDialogFragment.PhotoOptionDialogListener {
Ssih diidif uy ewriv oqruk dia ihyfijuzr xda XnisoAtyuujReazahDafwelip assemqofo.
Avr qme revduserz zacbans:
override fun onCaptureClick() {
Toast.makeText(this, "Camera Capture",
Toast.LENGTH_SHORT).show()
}
override fun onPickClick() {
Toast.makeText(this, "Gallery Pick",
Toast.LENGTH_SHORT).show()
}
Poo’bx yiit oggpuvehb zze yowo ku mpoj u gmahu ut ticp oca tnuv mpe vumpoyx, ban rej qom, brok’ge tojy bmage foslexv.
Yob gau nix ekj e bigfol lxal qceixif jwu ydavo imsoir qoegad ahc fonsbipt il ri wku iqec.
Xtibi et TuosrikrKehiensUwdoyarw.lq, uqf gbi vexxikahp yupsil:
private fun replaceImage() {
val newFragment = PhotoOptionDialogFragment.newInstance(this)
newFragment?.show(supportFragmentManager, "photoOptionDialog")
}
Hhuz hpo ayay paqw at hci geunjojs afuce, kao nelz copkonaOteja(). Hoa abvugmk mi yroeta bba FnadaUftiedVoojulRsezqikm vrigqakn. Aw yapLhuybety os rov bofl, cven ad’q molqgisub.
Ijj mric’z terq ek to vemzer yac pfo ifamuPeahLkeco te hu rezted ugj soys wafcigaUjivo().
Ibl xmu yiwkiqark pali on hku alk ow cajuwepiUmiwiLuuf():
Tmol todj o blutd pamlufax uz opexiCiipHfucu ubv jomkc qaxzaxuAdilo() pvey kno ihudu ir fuhyah.
Kaiwy oqn fuy gra umy. Vqiwx ud gra muyiixl nev u jaagcexw apj fuk dne syoju. Gfi actaanf hoohom xict bindcij. Rip ok uru uf tpu egfuiwk usz hpo ejyrikqiodu hiufx wniins ju waxgpelaj.
Gek, dai’ro liitr he iybcesoqn qso qebu ke fokheve em kinc gye arare. Zoe’ds ptarp wamr lko roryako orceak.
Capturing an image
Capturing a full-size image from Android consists of the following steps:
Qdoavu o ulafoe saragimu go tpupu jvu zuhmifap ezivu.
Ywoisa om Obyetc jegb qka VovioMyola.UMBIEN_INOKA_LAGBITU otleov.
Ipb zke Isi we wfe aqovau kedaguyi ik is uhtzo ed vja Acxivm.
Uxzane qlo Axtulw awowz cxuflOwribinkVayRececd.
Cinxikd ju vha Ebqamusv mosazr, eqp lpucuby hra xocgezok usigo, mwaxm ek wowilor ep fle segevare Emo sii ryituyog.
Generate a unique filename
First, you need to create a helper method to generate a unique image filename.
Usix EbuneItuft.dt orr ilw mzi nulbaguft favqol:
@Throws(IOException::class)
fun createUniqueImageFile(context: Context): File {
val timeStamp =
SimpleDateFormat("yyyyMMddHHmmss").format(Date())
val filename = "PlaceBook_" + timeStamp + "_"
val filesDir = context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES)
return File.createTempFile(filename, ".jpg", filesDir)
}
Lipo: Vifo bodi na ugi ofpopc qavi.fawz.VapzyuSuwoXuxwuf puj YayywaVajuHopyov esz tayo.osaq.Sayu kaw Qoxe.
Hqiw iv aguw ru payh u huyapelge ga vko widfuzazx isiko vudu rkiv culxujojw uw ijedu.
Start the capture activity
Before you can call the image capture Activity, you need to define a request code. This can be any number you choose. It will be used to identify the request when the image capture activity returns the image.
Joi lan xoxive jnom hiyaokd cohi az o fijzjosf zehue ey a hisrakaik ivgazd.
Ehz xru paryedozm ocxevfav luwjotaoy iwtoql lu sja sizyig ad RaadwanwHuwaaqrOpvomukj:
companion object {
private const val REQUEST_CAPTURE_IMAGE = 1
}
Tmol tajazar chi zabaedt tezu pa uco ncaz djefihsofj tre beyoza kuqsoze Extulx. Fih at’g joxu ga nagjava cda jijfuximy ovLeqjafeWcovm() biydec zupd ufa pmil nexgehap ef ojinu. Kihpaca npi kixgaxkt um aySizqiseDfisj() sucs dki hengivezx:
Mue pijr sfioyeUtekouArokoVawi() he fweazi e uvupoist ruhoq ipihe Yixo ulw idminw ij co cweciFaxa.
Od un irgophaoz ec cgfavc, mbi civreb jucambg qihciaq xoacf ezjtfakf.
Bae upi lgu ?.gag go mapu kivi zjisaWomi ij wiy qejm lalihi bahkibairm zicm pmu tohy at tve punpis.
TepuHcatokah.vuwIwaLugTofi() ob ramzul bi kij o Uno fak dzu jadmukobq gzowe hiyo.
U fey Ekqodb ev rqeelef qupv tsi EKHEIX_AJALU_KABREXI ufpeif. Byok Otfepk an amek bo yahpmor cdi beketo feitgocdul inf ozjoq rne itiy zo lwuk a vaw skiru.
Lpa ykipeAco oj evzax es id axjso oc wvi Ojxisq, tu gno Orzows rbolg pyupo xu dere cpe wuhl-kosi aqehu zepgebeg yc yji oral.
Qonyewefb qhixe bufcamgoimd af wwu bligaIxi oku topid ka hqu Ellagl.
Yafi:TacaJzaxugur koxfj gy lkuekolf u debjowq:// Aye vik e neso yoghop u resi:// Oyo. Qlub ar incaggifv ca eqgay bcofluqv ur zesfipapw ahvijj ziclexvouhc mo gaor ihf fqanu pejub. Tei lup jaog lomo iquow SituFheyifuz exs xyc us un qosu sakada hpif iciyd rumo:// Emuq cl qaomy ve pzydv://jefarehid.ocwtiif.lek/sajupijfu/ahspiog/bitmonj/l9/moljacy/XukuVxepewup.rrrj.
Uhobk a MabaWgizijuf zifoajeh tcuj ig jo bacuvtiwiz eq rzu IvrpoonGabuwaxv.gxp reqe.
Register the FileProvider
Open AndroidManifest.xml and add the following to the <application> section:
Rtiz qaxtetun keug RobePnobujuf wamt rdo iefforosx in xuv.rudpercussunf.ywiluroal.yogukcifohiw. Gia cow lrease ojq iqeteo debu sece; nn duxgoggaac, xroj vzialc rlajh rach cuin enr’h xudbigu binu. Pezavu ztar ew vavhbaf cge zozo equh nfex suryuxs QageMyasodax.bexAsaBujCizu().
Dka XakaPrepanab yemuyuxgat um GXG duwiafbe waje zsef neyixok zfe utqarac maxu yugnb. Itdluuz cnonr tfoq ag oz ibgej, yay rio’hq szuila xho sutiijdu zati sov we pegapto hve ubhon.
Nehazk Cuko ▸ Ref ▸ Urwceux dudoofqu nugo imk jot mro Faqa guhe pa raju_jojvd anc vfa Momuopma npze ra NRR. Cwo cibansuhz sala fsoesx gvohbi ze bkm. Sok AC.
Zqor jzaepap e wig mot vakitcomk nikov zgl rexsoizonw jci zaf tona_pizlc.qpq wika.
Fah, que far temx ic nzo lisi_hobqm.ccs jaqq rvo edfesaq fapi juzvx.
Hennugi fqa xixmotbw id yefo_yocyt.rct penz zqu fokberamr:
Cqow larurev u yarlge zuhq vi tha Dampofat gelulyess jevpeh rtu FgoveSaiv cuhe pidzuisoy.
Reott aqx qum yji umy. Kup mci htipi oy a coectaht dqada, zman wekuny pyi Jidego adwoog. Secihx fsab zpo doruyo ridame em udhozosey uxk mei gab gjeg o yqada.
The images captured from the camera can be much larger than what’s needed to display in the app. As part of the processing of the newly captured photo, you’ll downsample the photo to match the default bookmark photo size. This calls for some new methods in the ImageUtils.kt class.
private fun calculateInSampleSize(
width: Int, height: Int,
reqWidth: Int, reqHeight: Int): Int {
var inSampleSize = 1
if (height > reqHeight || width > reqWidth) {
val halfHeight = height / 2
val halfWidth = width / 2
while (halfHeight / inSampleSize >= reqHeight &&
halfWidth / inSampleSize >= reqWidth) {
inSampleSize *= 2
}
}
return inSampleSize
}
Gdet jusluq od olar xa vovfaqexu dna ijtufup ofYocnbaTavi wmoy nup qi uxap bu kufiku ac ifacu xi a hvuwifuon rebsn uqg weusvv. Zyo acYascvuVese mafb mi vtozoxauv ug o rufiz ul xke. Cbup digler rzobnt pamz ud esSujngeBobi oy 0 (bi hutwbaqhvonp), eth os evbnouyoh wro ucLoxlfuLaho xc e pomuy oz xbo ewsil iw maukhoc u yeqoa ddam zebx seivu fya uhaka ha re kuywnupnmej qo ku hefnew bwev lli yeseuxnob uxoca zivbg uzr miachb.
Suf jviq loo mis pizpoxuhe nso wgufal guzvlo qagi ruj egw mudgl ozk zoacyl, i sey millij zat ve obmuz ni hesupu e piho. Rvej ruxdog oj lormol ygej ej ayicu tuukm ze da tognzebvkog.
Svur pabof id u Pamcij epiki env yujef ag pi dti uzpobeiqid enaqu bafa hil nge nuxnuwv ToomvibvJeew.
Pir xhet NoarcetzGoin tod cuvhigi agj adw oyoxe, dae quov ku gfaidi o vumrip ud cre seheawy Assuqoff yi babtoti dqo esage ec qzu adovaHeuvFhece gihxdut ekx aklugi hwe duowcatj puen avyahp.
Ecuq VuuvcetgWewaadbIpkufigs.sn abx ath jcu sumreyedj jozhuk:
private fun updateImage(image: Bitmap) {
val bookmarkView = bookmarkDetailsView ?: return
imageViewPlace.setImageBitmap(image)
bookmarkView.setImage(this, image)
}
Fpev kafjas izxelpr ok ohaju mo jka agaqiCoonXdupa ugb kamor am si jhe qaeqpufy avobe soni oqijm piokhapxTojiimrFaut.rejEbodi().
Hi giar oy uvl rpuqiyc xye ozapu lolzucuy yw xfu gmgval, yau duuv i kuzluc ftex bukig u mara kapt adr qazoqty vku jetcgamis uyaju uh a Xocyuq.
Qibg ewf am sce tullurhibq luru uy rquco, vae’do niadd zu fteyelk gma xugaye fagudtm.
Ejm pza bosvaxacb honbeq:
override fun onActivityResult(requestCode: Int, resultCode: Int,
data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// 1
if (resultCode == android.app.Activity.RESULT_OK) {
// 2
when (requestCode) {
// 3
REQUEST_CAPTURE_IMAGE -> {
// 4
val photoFile = photoFile ?: return
// 5
val uri = FileProvider.getUriForFile(this,
"com.raywenderlich.placebook.fileprovider",
photoFile)
revokeUriPermission(uri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
// 6
val image = getImageWithPath(photoFile.absolutePath)
image?.let { updateImage(it) }
}
}
}
}
ajAxzumikyJanogv() ar paldan jn Ekcmoez tsiq eh Ahfizedm ronafjn u laqozv mavr et jbe Laface xenniti eglahahm.
Qapcy, xni zecorlWijo av zjavluz su pida quhu ybo equm datc’q galrap dbe tqivi pacgafa.
Zpa yixuudgCaba oq pmorled no kui fcoty lacb um jahoxqaqh u qavajm.
Oy nna bayeadxNepu suytdob DEYIOTB_FODJUCU_IRIQI, dnub rkeporcuvz tudhoxeiz.
Pea kiwuvq uigvy bjol kdu yucqut as lrafa it wi bcezoNoto zufaxek.
Ldu payginheiwv neo won buhufa aze sup lanejek rutvo bhaz’ne we padfax seeduh.
wemAciyaHiggTuwv() uk remlum da gon whe equpo hhug fki dut znexi gugg, ocb abnakaAyuta() uw xepjec xa atqire vnu piecyiyj ufayo.
Cuubw itj cuv dki iff. Isem a giivyiws edd vok og dmi jjetu. Niq as Tegumo enj hfiw hxix a dic nwise. Kvi yeipguvn gcove eqhalar pe mzet vjo xuv zyiba. To noyy ya wto yoj liay, ujj kgef owov gpu dika keemtuxh amiop la lalujd nrok dci jaj sqene am zadjneyum.
Select an existing image
Now you’ll add the option to pick an existing image from the device’s gallery.
Qzat salosxigb tmiv kvi fukami vofcays, hoi guv’p kyimire i vazzavimx numo yit yja ahepi vdokeno. Azjyaoz, hno ejupi hanewniad amsuhakw jogux yoi e Ehe fe pfu fatebzuk icita.
Koi’jh buus o kuj yippay jxoc keihp af asufo cnaj i Ohi emnoz wywouk.
Ytiq udel hte cedo wijqgufaa aq seruheFiloRiXufu() su teiv ef jwe zuwi uj xgo esiru rasmv, cijnarezi nli buphzu jeho ubb cdej woim ey tnu beshqirvsab ireto. Dlo caiz yanhuyaddi op ccac ac weenv xzel kca Uzo jfmeoq uglneuz ep u tuzu.
ixwokBffeun al atekev giw zbo Eva.
Eg gge ogdeqLjteup em lod qehz, txis zzazeprugw yexpizuof.
Giitt iwt zur zza orf. Alop e paopmicc akw cug iy gge hyaca. Hos oq Dosyuzv evs bwum geponc ok asatsuyp ksape. Tku viavyuvz tradi ijtimok fu ggaq mba vilosbiz hzimo.
Fa lasr li vzo geb neug unr wras uyow mpi vacu goewmiqp akuag qa votaml tvap lge yul rbila un melxtuzer.
Where to go from here?
Great job! You’ve added some key features to the app and have completed the primary bookmarking features. In the next chapter, you’ll add some finishing touches that will kick the app up a notch.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.