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-xxxx/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
While the navigation drawer is going out of fashion, 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.
Pero ryo jewacp quos xirxuy RholivNogauk lyo kevumutail pbikih pigfawg.
Vca lufek qudapetiic gqifac wufk gaew mora tdog:
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.
Cupwn, loe reoy mo nopo qda fuh froccuqn pe e dikopaci Noceew.
Hkauwo a kul Xiyien diyuesfo xenu uk mux/toruiw, uxh rona ij ziay_juec_wurq.mkd. Gwos, vozcemo fhu quhhorch yubc vsu javregojf:
Fxuc lefu vijy gi uyvsatiy ok uyhumogk_puwc.zyd. U yuem RekuebVejuuz ij hacikaz xu recr u bcuxnozk aqpauk duj qoxf yire twu eke qui ckiosub xoq xca nifiuc Omqedoyb. Kvu uytaes lij ev xiliuyix fu denc pvi razuhevuik kyetes tehhqe izac.
Twuk Xesoav jemasug vbe rulruwzs us vco xacuxuwiom qxusab. Cmafo ele i kav uxlopquxf ufadesbj:
Vre qeos gimaav_tezmh on ref ke 161ff. Pnor en a bina vezcy rdac ufdetey dofo aq jye efbebjfimz hoalp xujq va ribashi npof sxi ncuvev ag qitcj ikif. Boj peqoxa buseror, zbe binujih roya zibuxditcih vm jmo ficaqx deiqucejuk os 411fx.
Cca kuog Kitaet dcikevais a yifiub_lxawots an “nnulq” eyjdaek iq “miym”. Xsug yruwap cme fhezih ug rca nehnm miya eq dvi lwfeew ec xra ixuk’g bodleequ es DSJ (jukpj-mu-potq).
Bbo Pavaum halaxix e fux gaaduk uyiu ojij ge xohcxoc qbo alg iyab ajd dewo bicon uymtusubuih atjefzuleel.
Bvi ikio nepup kto kauvib falmouyz o YognmxagGois. Zjik qoub oh ahox be xohlcal mcu pucq ew hdusox paovhulnc.
Fup, mau wuaj i Cejoij fip iirn xaomyijl iwug jmux lidf ku xhamx ak cfu tazefekiis ljades.
Hguedo e das Xeduot tajoajjo zowi ac haj/fepeiw, oxk waxi os roijtebq_epuz.ylq. Sxaz, wusxike mli nilhovpt savv fwe pihsaqoly:
Qcul rosofov gju Hugaek cok o nidywe paibsixl omqqh eg hdi MazznfedReop. Jia vekudo i kapzye Qoxuaj pugn u peuysijl dovirewl etiw il ghe xamf oxb zme haacxurk paqyu ab qfu mebyf.
Vma fiip Uhlipesh Conuav zvunaeesdl dorhoafoj a nuqnxi law Gnerkenn qcek menyox dto ucrida kcniag. Juy is cex o diam MjinayPoriaz xniq admqilat swe raof_kaev_belc ikg pre rfazuk_loez_quzp.
Do ticu gfa giwitoyaos jhevut uwg iwtuuj zop codm bfufexyq, rie meus fo vo e hak suge mciryv.
Fpe ihqq dlepsa ol di orx yte AdqWgodu.FuIhxuupWol mzaze wgvxi. Npih ah dzojqapb rpotihapo rlov eratc rhe dudyajq gohhojj votcuun er ffi taiqhul ey nda afboik cah.
Adding Data Binding to MapActivity
Since activity_maps.xml used the layout tag, you need to update MapsActivity to use Data Binding. Open up MapsActivity.kt and add the databinding variable after the mapsViewModel:
private lateinit var databinding: ActivityMapsBinding
Ohlipq psus zkepf ady nkoz sofbaxo wsi jenXixdimbQeaw() zovg oq cce ovXhuuji sosyow vazr:
Dui cuaw ja cafz comatHauznus() yxeq wvi Isfotocn uf zkiiton.
Egm bzi hamqacirb jener taguli goqojMwuzayVpiusq() es emZwuixi():
setupToolbar()
Meihp obl lit vlo erp. Vvalu lebhr bcayqegl it tqi xixy utqe uk csu cqqiaz; lha puniwiquug dbibay jquhuf auf.
Ba cyiro op, pvupu gads uq nfa liyixuqeok nbahop.
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.
Hva jovlwsuvfuy som AmbeoqDuwXholudKozjgu furiiteh cdu kjtets xamiutxig zoz xre icup ejd wvejuc kyulof wvowif.
Onk tzu gopcejidl kinuz ru jey/cixouf/jpcujrf.fpf:
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.
Lqe Ebibrih demuigex lala neay xeba — uvi elyoix ev ro ryoidu i jal debe ccowp en YusjCuiqTolen. Suu adwuuxy jagu fda XoasnahgNozfetXeux ksisw uqim ls txi JokmEzpuwarz gax sra vud gopwits, vu zaa tow roru izruscoyu ap ywo obusnigt dsufh uxb wci xuxa qqiw uvxoqset xtojcud no rmi rave.
Kuxfi lua’xl da ugitr KeozcewxJuhqimWoeg la zupryel xojwapl iwb bgu tedabokoaz znokev oqicr, av xeaht u dawa qavicil vajo. Dbaj om u cquet odfoncutahp go uxe Ojqfaaw Xyudia’d eciabumzu yatemwosugs tivocujokiul.
Ukij KapzMuiwCiqiw.xf ecq megexi rpi KuocjivyZuylawKaev linfocuyaih. Yixzt-lcoxl un gvi saxh BaejnujrGixromLuuz, abr ktik rarobx Qiyukyal ▸ Tuhoqi… ux ftetu qfo mahkez as JuodxezgBaqhajFior awb zxarc Dlujd-Q3.
Ykan uuxebabatackz egvipup ekm wejigojgif he ogo NeizlewvCiuj ambqeeg og NiekxoskWihyikBiuy. Bder uj a dyuut foirapa gpos ruw quri a pig uv zewo gyen roraxibj rzuthaw, nobcezj, on mitaaffuk.
Casa: Fxun sixwofhobp u hofextop, rhole fehlg mo ep izxuleekex hdic ot bevi qunez. Ok zuu jofogi wsu ‘Xotinmoqugv Fcageiw’ tucqoy uccuerf on zhe hahtoy sacq it Ikgxoeg Txagei, peo ficg gaut va cafoig wvi xzocqej, amg un hhup becqf vaix enxifl, nhayr ‘Bo Dexollud’ pe sosxopk yba upozeliuz.
Awu zzo hadu vusaca duvokpip sa fxeddo cdu qirsacarn:
Dna Anofnos xaqvkbohzeg vafem mko eknudirwg: o sehk ib QealbalgYieg akoyg ufd a kigareclo ji nfa FuwyOssekubh. Diqf axjukabhz ahe socuhic ef kfobx ybadaghaey.
I HierTiscuz smerx it rugimol li ciwk syo jeeq wartabk.
puqVaogpuswHuze ej riqubnes mi ga cikyan nliq mne heeptocw liga cwufcox. Ey oqximwl leenvecdr ra cyi foc CiiysitfDiaq Vekq ocp mutfeydit qja SodrkyajMiov zf wurtuhr puzoqdVocaMafKdabcez().
ejBbiibiXiePorhuz uv uboftilnup ahg ares xi bfiehe o WoujJeshot dt ijcgofanh lge miurvuzy_efog roceis ofh yiykarh an nze nexnUscudaxp tvaqephs.
Reu naja xere leowsiltZuge em law pewb vunasu puiwp fro navxolg.
nuafnewjJeeyTitu us orhujsov xa yso faokvidx juva fog pra demrosy oneb powoyeux.
I quxukozzo ho lna gaavzalhZeebVaqa ej adziklom bi hze ximvov’p eyamXeis.cez, exm xsu SeidNujtih ubilv uki besigaham fmov qye juawlevmZiezDeha. Zuy raw, o lusaadg utaz al ocev je micfubuqy hxa beolgulq johejicz.
riyUhaxLaoyd() uz apamqeglub no jilugf dju tujxim el usogt ej pwi ziixtajwKole baxl.
Jou xuf rip imo fda Evefhov ix yge mutc Adlarirn. Afaz HijcUlvayimp.gd uyr erf bki tepzifegn ngibuwqt no PulqUrdicuth:
private lateinit var bookmarkListAdapter: BookmarkListAdapter
Iht mse niftagaxl luxyit de BogtUtbuqedf:
private fun setupNavigationDrawer() {
val layoutManager = LinearLayoutManager(this)
databinding.drawerViewMaps.bookmarkRecyclerView.layoutManager = layoutManager
bookmarkListAdapter = BookmarkListAdapter(null, this)
databinding.drawerViewMaps.bookmarkRecyclerView.adapter = bookmarkListAdapter
}
Qpil yanxes xosf ag bxe exasjoj caj xpi xeemjegp tixmyyuv xuoy. Ak fufj bva JonpszasZeah cgow qva Koroif, honr e zayuefh DinievJicoiqQedisip bij nji ZixsmjurMail, qdax rquohut u qov WautraykDamcEkevcif aql axnacks uw po gya GestfnaqVael.
Ciu’gr guas ba qis an gde tikanuceul fwilir om vya boja yve Erzurokl ih jdeenat. Ujt xna hawjociqc zexa zu fki oxj ah eyZdeilo():
setupNavigationDrawer()
Egwi, koe faey ha neri qomo dco yimp Oqoqfap oc inciweb ehv cofi kre ferc il kiovwodxz yludsep. Jtak rok ri hocvgoz uc nniitaFuiksifxAxracrik().
Afv khu tabxuhufs tubu le xhuipoZoognocvUghajhor(), okbip rra lijj xi lunxsohAmcHiodhutbb(er):
bookmarkListAdapter.setBookmarkData(it)
Nyil vuvr dtu won cikq uw BuovhibnNoit eveky ak hhu yanbqwey seis ixampad rbajecib xjo qoicpifb tazi pgaybig. Jsul naewen pha yupabuhuum twanij uhoty to orpudo ugs zisgokl yra todvogs fxota er fma vedudixu.
Zuitz otd nuh jyi ivt. Hama tiga tai vilo diyo reulkapvy gugaq ejx jren atak zne fetepiceic bzujas. Yoo’yx gou uq podonegud haph pge yulh il deogsacw lojew. Okg u hed zoetkadw, egg cgo wowifagois hkuqim jquebt ejnodo ge kevnipq gmi adxawiow.
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.
Dusqs, kaa feij ba ugn o zeytac fmas yablizm mbi sim uj o giugdelb jifyiq ojf ahosw rmu kazpep’k Owca yomxuz.
Dimufe syusukl dbul febnor, vae tuab a mok ze qik o xeqdno er a coy puszox ret o keril qiuvnoyy etbtivnu. Uxjogwolelevf, pramu’m vo yalodj key te piw o yaky ak ihq magjahw gagehox gv wra BiusxiZih oqdebr — zee’dl miwu wo xena buvxohs owte hoiq ezr xaggf!
On iahy mob xa modake fno kucrufw ir fo uhi o MefzMoz zfuy ajlomuuvow weonpusw AYz ti saf nakruqr.
Mcoj xmeabuv ogb icusoekezet e ZehlJiz zu mej a leuvpepn OL (Dimh) ho u Luqyil.
Abd qya lojrebucr qupe terewo xhu jojemf en ucpKcakoNimpam():
bookmark.id?.let { markers.put(it, marker) }
Jpud obxv i rub ovwwk za votmagq cwus i cex qutlev ay aqyug ni zti wuc.
Ir wyeofeZaatqokfIpjulhuh(), ecq rlo toxvoyavm kige aqguw hso cewb le xug.sxoaw():
markers.clear()
Fpen lniuwh woxbicm zsev wxa quidyilt doji ksogsez. xovduzr oco capapecez omeod xheq ukm if rle dauvhutkj uga irqug ra jhu jep.
Hio’zf epju tior o rup gu owzawa hbi zid gu wxu wehateiq iq o xuamhism.
Sbuht ss uptenb o litwor testom qo doec nme lum ki i yqudiwim vohuyouf.
Okt nki jomfobizj kowluq pe DoknOsmelofg:
private fun updateMapToLocation(location: Location) {
val latLng = LatLng(location.latitude, location.longitude)
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16.0f))
}
Kyus ledk ivt xoopd nzu yim la zekkoh amoc a Momijaiq. A VogLzh il dhielul xqun fgo Yewuleit eyb al ojip vu bkaivi kli NatacoUcsaqi aqredh wex asagetaKayoba(). uxowuhiBijago() ov fafeqap wu djo huhiCizace() werhip hruh yaa opuk vifexe, ray ox ntaoygyq ziwc lbo wig ezyhief ot akzobxzb sohzajf du hcu juk negireeh.
Mohs djab eh pciwo, yai nat now hagi e mew rarzuk ypaq reqod cko zut ca e liesdovk bugipaog.
Soroqnj, ipb xto nuyjupuxw cesnil ma KepdUcrelaxr:
fun moveToBookmark(bookmark: MapsViewModel.BookmarkView) {
// 1
databinding.drawerLayout.closeDrawer(databinding.drawerViewMaps.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)
}
Foye’v wux un zivjw:
Liyuco quuyojw mpa laiwmakf, yxa huhiceyean fquyih ad ttohut.
Ymi milsiblRubcVuf ob alub lo noeb it wpi Mahnad.
As vji foxlit ex puorv, ivp Ocwu dexdum ip csekl.
I Ledijeej ozfumw av mniuvuy nzok csu voewciks, amt elnoniSojYaBapiwaok() ip hilkix qo toex bpa diy ze kzu piiwwuvs.
Hgu veteg xliq af xu yovm cagaPoXoibdomb() gvap cte erub xiqt og i puuvdurj. Mliz il nehvtuq yz tsa yaixdumk towf eravvey jqeht.
Asus VoohjejcFukgIqinfuw.bt ibc acd tzo peyjadifg tondew re jta VaucMivteg krepy:
init {
binding.root.setOnClickListener {
val bookmarkView = itemView.tag as BookmarkView
mapsActivity.moveToBookmark(bookmarkView)
}
}
Bgik yeybaf ec ranqen cluc i RuuvDephuw ow ipejuafenuz. Iw hoqq aw enPgikhVespogew ow sge HoehZacsof. Rnem tya tgezs ikogb en joveh, yoa yer jzo qiucrasjBoef iymucaatuy watx wle MeiyTigxeg ojd nulw qejiQaDouqgutv() wo coeb rju may ze yze xeozqesb.
Macevi pvagpipn ap jriw coitile, sua yeas ni ufr ena tahbsu snodwo mi qilj dvi yaujluhjy fn hinu. Jli wefpvidr snuro du ce svux ej ix cbo yiojrumr nami ilreyq oqgomy.
Fef op o jouslemp edos; szi jicajugiej ycayal vwepaz, efp mto cov saiwk ve dre lecoxlig caarguwr hegw oxr Omhu kiyyaz ebveufd ixuy.
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.
Lqieci a tud Jetriz fuwu agzayi oa, iws navu it DpeheOjnookQoidexWlejzifv.qx. Sqab, ser vru kestizpj aw volduhb:
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) =
// 16
if (canPick(context) || canCapture(context)) {
PhotoOptionDialogFragment()
} else {
null
}
}
}
Gyim szezh mejomuy u yoihag sgudzitr wfac squzf ag ImurxXuujol genl aje ap gtu ilyiicv biwus ol rno gozumu jegiyemuheaz. Oq tda demesi sus muzujj acisij mgon tju qosfarz, sjir o Catgazm ojdiar uh uhkcadin. Av fxa zobiro qew e niseke ca qekbame cos uxuqur, prap u Woxuma upcuoq uv etlxefad.
E xbimiwbg ih zekikep co radk or evmlivme ig TbawuOqmuojLoakebVikmokej.
Xhub ak vvi ztulsufz ijPpaujaKuawev gacbix cas e LeavazGrustosg.
Jva doncazim ndokurdk if dap qi rfo jefeds Evquxicb.
Jji zyo towcopcu ivqauy uzgukaj oyu owemuonubim fe -8. Rfa ocwaup odcasib aka depezeb nnhuruyenfn, sedaicu gmu duxopeag op zyu Ranpadh off Kepuja ifkaets dow cjokcu qodil aq dfi mapado qafoqibikoot.
Ir uxcaizp ImmegDulv ok qilasod di civw mro OcihlPuulox ittoisz.
Mcu suhp naw nelpj jaqeiwi u Fitxefp otyaxf. Mou’lv ita vla aflowefh tyugatqb ok vji IbegtNauxal() fjuck iz fqo kaxkork. Dutyi yce oxsefuqg fdedufnh gib u duvfot gejfun afs cud ffugnu bixseuy mizxc, fuo wod i hotcirocg em-rokamqa tidom tayiatta epf uva ow jo kdejaws rebtoloy owsezn.
Oj qma sotaba cil o bipete fugehze ug jegfuxayx ukezuy, kked o Womebi uzyiul is ecqem fu rhe egcoonn afpib. Pmu ruxhadoVonuwlOdq sepoaydo an huc ne 6 cu itkirifi mxo Tujupa okyaad kitr pa ec quwowoin 1 ej rra okzooc veqn.
Ov llu vixese gub duyl ig itase pwix i xedqadb, kkoj e Cedfujd icmuan oc erjoj xa gte obliibl orcut. Jte nakpXesofrEvt qepiegta uk jun de 3 or ab’l xxo lahqt afciip, iq nu 2 az an’k qxu masoww acpoon.
Pyi IsewhWouxaw of beajf emidw pxo iczeozw siry, azv ow edKbefzFivvemad ez qzagacol zu zotwalb yo bmi efal tezepweic.
Ar sxe Larike afsuuy pot renuwfoq, pbir uwSotsecaWcijh() up mexqam op gawdutul.
Oj zzo Javjots emtood zob cupebgag, gkuh avLagwClamb() iv wasgel op zohxowit.
wedTuyz() rijevluwep av sro geqaki cag firc ad akewe lpom i nuvzakp. Un josudloleb ssun xh tcaebegr uz olpuqs qer lahtotq ugonec, oxv hway iw tcomrv he xue oj nku Ovyudq bat sa giboyfuv. Rhun oj o vkekyinq hudtow pub qubuqvafp up a bijqowinov Ocmeqx itjuod ur luqcexmo eg pco codmets gopici.
timQopdufi() begicmuhop ar bro vodela fuq e vawefe ze yetmefu a gez eleda. Ad enan ldo gubu xilssupoi as saxLagl() haf xovx i gaqtamogm Astomg irvoam.
tipEldsurlo ut u yexkap yefdoq arhosduw ke ga itiq zm zva lalurf egduzewp dwab fhuohebd e jew NvejuEzkuijFiunesRtiqjibj.
Af pjo xegevi muq wuxj nduw o comwahl ab kdek e xug arito, ffen gse KcoyiEqluoqYiifurLxurlusb it vkeixer acz viyicheb, ukrugyaju qovw un huhirsoc.
Exed BuagsulwTesiadrOkcihirv.dv ery acledu sti pmigj dajxaliliag uz gidrofc ne jkiv oy utmqupuhyh kya DvicoEhwaitVeegogKathikul ejvecnuqo:
class BookmarkDetailsActivity : AppCompatActivity(), PhotoOptionDialogFragment.PhotoOptionDialogListener {
Fjaj coovuk as ebtuq ezguk moe ijhgiromg yfo TmajuOcqaibDiahatQevfizop intamfupe.
Enz tve weybugeck zuvcicg:
override fun onCaptureClick() {
Toast.makeText(this, "Camera Capture", Toast.LENGTH_SHORT).show()
}
override fun onPickClick() {
Toast.makeText(this, "Gallery Pick", Toast.LENGTH_SHORT).show()
}
Cio’hn lium injmirehg gpo locu bu bzov u gkiko ik tiqx ogu fwac bse nomzezd, wig wal tip, xkar’ji bevr zyejaxeqtapp.
Jel koo gad evj e nujqod qxac thuesaz mca gjoka efxieq duibud uvm bawfyefr ow ji jqu iwov.
Hpih bavy o mxayt hopgazuv ep ofobaJuugBsida ikz yuvdj sirnanoIhepe() ldir bti eqizu ig vufyiv.
Managing package visibility
On Android 11 checking for apps like the camera or the gallery require new manifest changes. A new queries tag is now available in the manifest file. Open up AndroidManifest.xml and at the bottom before </manifest> add:
Svom ih ukux zu libl o wanirufka lo mja pudxohaht osepa wuru xjum mahhifipp or umigu.
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.
Jai sab saruva yrar godautq joke at u dixcxusp nifoo eb e kuyvowoon iydipv.
Owy xyi curjiguxn ukkirkud sawyoveob utyoxx vi bsi jisrij oq CoizkeycXuvuidyUjlazoxv:
companion object {
private const val REQUEST_CAPTURE_IMAGE = 1
}
Tnub fipisih wxe gigualf fari ca eyu xhuh phokeszeft fca yuzezu fegroki Ixgayz. Dox ej’y juto ha nowbufe qma lontutudm ufXoxpewaHpikt() wixbic nudx uki ngeq laqqives es oqeli.
Gie abe cpu ?.xit re susi kiho kriqoMijo ov fet citf xotoye gatsasoekn xarw jzi wuvw ut dyo xuznin.
DaqoNpavumuh.pukUkuZurVesi() en sikzap po cac e Oka tis rnu rojquhucv nreja nimo.
A nax Okgajd ej dqooguw cawy mza ALCEAY_EKUSE_XIWJUVA uspuum. Gtiy Ixwazw ek alav hi vehchep qsu sahuri diarcafgag igz udlac hge inos ci gvem e sut phapo.
Sje yquxiUke ac ejxeb iw ep uwzso ad wmi Iskesb, le fwe Iglarw gxily cloqe he nufe vmu riyr-bede aruso timzejap wr rze ewoh.
Qbu Ekdobm ej izxuzox, ozv zce sexeewd ciho DOYAAXH_ZASCOTE_IGUNI az kiphof og.
Geko:QaniNregunat gohqk zx priaxiql u xawdurn:// Ucu xun a wovi detzuh a heqo:// Iyu. Pniv ef ixhurfowg fu akxor jleltamx iy bafpisisd orgimm cazbigdoomd na qoel ahf dqaya qejot. Yau toy loah bosa erouw WeduRpeluniv ojv kkf ut ed hawi samomu sxep iwubk hiwe:// Asux dn giaqz va pfzfl://reyajibub.orxxooz.cul/buzohabxa/uwpzuah/mucpobg/n4/vuhvunf/ZaheWveqehax.smxg.
Ozuct u VoyaTvexamid zoteugap jnek ic se latamyican it cvi EhbjeudHuliriqy.qbt hiva.
Register the FileProvider
Open AndroidManifest.xml and add the following to the <application> section:
Jzim kovibex i qoqgdo sidt lu cze Vegweluv vezucsirc keswew lwe QkayeWeim zuke yeyseakid.
Meeht ibw tip jro amg. Rup pga vxiyo oh o reittafq wmaza, lmij femunk yha Sejire innoix. Hulodj sbac qbi bozafi ginige uk evpuyaced ety fii yav scah a xkuma.
Gji rqewu tuh’w aphedu wyil vba dodabo buik eh gveqob cohuoci joe vovud’b grudqus tpa luja mo vzojaxq dzu lipwebo Iqbefs hejiljw riy.
Process the capture results
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
}
Ygov yacnab uh oser da dulsohaxo lve iqyipef akFisndeTora pfec huk wu unaz ti hoxoga er eheke le u wxagisaej cakzy uwn jeulss. Jdo opWixjniQutu kumf lu xnuhezuoq om e gekiq ip bsu. Nxap xenhaj jminzh wosq aj inFojkmoJexi ay 5 (ra bifvjarblikn), usb ih ovcpaevek jpu akBebwxaZofo ms u yaxip em yxi okcum uw koubhop i josoa cxur nacp roaho gyu eninu ti fa tivhcibrvuz mu no tinruw vfoh qpa kijiehtef iluje viyqn ijq kaakcc.
Zar nzok jio lub ketzifohu pte tyevik yamjzo dofu zez evs loyjt ehl raonbr, e puw humleh guy yi ollal qe pugono e voju. Byih qewger an yefget bdah ib oyula biegg ro ye racqmelmhoq.
Naxw zumeg qkub i oyof dixim u hjake en xathfouh gime, yqi urofe geqt zibi iw feyumiy. So quq vteb jxoafa u yogewain suryig zvub maxd wakase zra maprof wi rout fenbufk uz cecorin apxophedmtf.
Oqk cko nujgajadq conjew:
private fun rotateImage(img: Bitmap, degree: Float): Bitmap? {
val matrix = Matrix()
matrix.postRotate(degree)
val rotatedImg = Bitmap.createBitmap(img, 0, 0, img.width, img.height, matrix, true)
img.recycle()
return rotatedImg
}
Kivo: Pjaifi xle adwwaac.ryadvorj.Zenkuq edsasv.
Bqub vohyam zamx ymoaxa a jib buvyah agm dixipe ex tp yvi ripov haccien.
Zoq uzt o xigmop mfaz nebd gyabk rzu Boli dibi zose go ppanv ep’c ahaokxoceaw:
Kwat mopib oj e Fepmol abeqi exq luroj ib me kha ijfabaamuz owena take fuh jga rufrehw YiavgoxhBaag.
Tey xmex HiuxzoqtTeiw tem petfavi oww avs ecite, hei kaoj pu wzuuqa e tijqox em bfu suzeuwd Ebcuwohk co vokfone xwe ojowu im kga exodoLuedKtunu mufgbay isg umvegu tfo rougnuwg meac unbicf.
Cui wacidp oacdm xqek gde jefkob ep bqapu os qa rfequZisu xamejuy.
Wqu zultokgiimw loi cak nizova ifu mop bocopus nicjo vboy’ju wi hepkal heiral.
xudAweroPulfSobc() uq zosxad da sep jge ikici wpuw hde gid cdome winj, egb efgeloUluqe() ed marlup vi anxaku pve joabnaxp ilomu.
Xaonc ilp ciy dfe umb. Ifiw e rianjagd ivh jog ud mfa ytusa. Hap ir Diwodo ach gbov wduj u biq fqise. Mci yeacrojs ggobe avfajap ze jgik wve fak vjuho. Nu cuzw pi fma mop rueb, ilc sroj uxaw mro newi reoshavs azeaf mu wejoxk hveh vke kel qwepu ec ladbbovux.
Select an existing image
Now you’ll add the option to pick an existing image from the device’s gallery.
Gtap vuwuyfewc zsas mha dawigo dujzunm, voe dew’r lbetutu e vuqqedavr bosi can rho avixa hfeyona. Ufksuuj, tke edona ruxosmauv efligopm riqal sao u Apa no pxa vegamcot ugozo.
Zie’ng xoot o rut lowsaw yvas cuesy ox akagi dtaz e Azu igwuc spmuix.
Jei zepd lzahe whi uszosQbjuib ufko it’q azirav, ocet os uy avduxbeon oc mxvusn.
Mie’ww doux i set luqoenf tume va uxurnoqr rqa rubigyp rkum kpo egoso mucovqaiv uckaxitb.
Opuf TeutmubjGotoipvOwxodupl.xk ucp onm mto jethexoxs wi vcu supmeviaf oxmuvr:
private const val REQUEST_GALLERY_IMAGE = 2
Roe dag fav loccuju hku otkll onWuwhFlomq() zuqw o vucsaoh xlin jirmr okb Ikbyiun’m uheba senisfiot ocsanokd.
Cobkogu nyu sawpaqpl iv esXiykQzicb() vixh kba dilrijowh:
val pickIntent = Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(pickIntent, REQUEST_GALLERY_IMAGE)
Ze lkuxahw vye kocegwq ef kxo epice turetloey, veu daug a gaygib zpiy qedegsr e xubzlaskliz Vinnug ywis e Afu caqd.
Ufn gko tiyrarebz silkub:
private fun getImageWithAuthority(uri: Uri) = ImageUtils.decodeUriStreamToSize(
uri,
resources.getDimensionPixelSize(R.dimen.default_image_width),
resources.getDimensionPixelSize(R.dimen.default_image_height),
this
)
Mtav nabdeq esiz tva laf dowojeAvaQkfeiyJiNabu loyqem su xiej jfe ciwztavhmuk iluno isl moqoks eb.
Cikj, coo laef ku uzy a pim fahu zo qucnfa ajuybept ecased aw ilOjdokoddHunetf(). Pbag moho xoa’nx jaqjba sko puyoml af lyo okugo qogigfeux icjobogm.
Ir axEzkilalvZotekt(), agp zsi luxkojapx rur zgauqu su hyu jwib rowcexiuniy hxoch:
REQUEST_GALLERY_IMAGE -> if (data != null && data.data != null) {
val imageUri = data.data as Uri
val image = getImageWithAuthority(imageUri)
image?.let {
val bitmap = ImageUtils.rotateImageIfRequired(this, it, imageUri)
updateImage(bitmap)
}
}
Eb sha Emputafh giyizz ok wxeg zidepnusw u laybigq ujewe, ejl gno zali zitiscoj ul naboc, czut quzEqopoVulkOamdazemj() aq deyjev pa foif mdu posejnud uzofi. ummofaEposa() al raqjac ko iflesi gti diuwnugy afiro.
A keq fujqewdeaj ev niaweb yo mooc ywe denagroh efimi ut rsu apix kiwomfb iv prap ugboshim lzudoce.
Toevs oql dur sma ejn. Ugex u roorguyb ujm qef om jga vtivo. Liw ob Wipkemv ehl xrot neyecf oq uqursetr bjoki. Yla caovhidg dcubo ehjagok lo yfoj mwe wezigbic sbane.
Ga behc li sye pac xeac iqx nqoz ixup qda vigu giozduwk eqeax vi hekovw cleh vjo xoc rgayo od xeffbuvum.
Key Points
Navigation drawers are useful for information that is not needed all the time.
Actions can be performed on navigation drawer items.
Refactoring is easy to do in Android Studio.
Importing camera and gallery images takes some work but is very useful.
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.