Pole haruldane, et arendajad leiavad, et vajavad a Sibul komponent, mida kas ei paku nende sihitav platvorm või mis on tõepoolest pakutud, kuid millel puudub kindel omadus või käitumine. Vastus mõlemale stsenaariumile on kohandatud kasutajaliidese komponent.
Androidi kasutajaliidese mudel on oma olemuselt kohandatav, pakkudes võimalusi Androidi kohandamine , testimine ja võime luua kohandatud kasutajaliidese komponendid mitmel viisil:
Pärige olemasolev komponent (st TextView
, ImageView
jne) ja lisage / alistage vajalik funktsionaalsus. Näiteks a CircleImageView
see pärib ImageView
, ületades onDraw()
funktsioon, et piirata kuvatavat pilti ringiga ja lisada loadFromFile()
funktsioon välise mälu pildi laadimiseks.
Looge liitkomponent mitmest komponendist välja. See lähenemine kasutab tavaliselt ära Paigutused et kontrollida, kuidas komponendid ekraanil on paigutatud. Näiteks a LabeledEditText
mis pärib LinearLayout
horisontaalse orientatsiooniga ja sisaldab nii a TextView
toimib sildi ja EditText
toimib tekstisisestusväljana.
See lähenemisviis võib kasutada ka eelmist, st sisemised komponendid võivad olla omapärased või kohandatud.
Kõige mitmekülgsem ja keerukam lähenemine on luua ise joonistatud komponent . Sel juhul pärib komponent üldise View
klassi ja alistamisfunktsioonid nagu onMeasure()
selle paigutuse määramiseks, onDraw()
selle sisu kuvamiseks jne. Sel viisil loodud komponendid sõltuvad tavaliselt suuresti Androidi omadest 2D joonise API .
CalendarView
Android pakub kohalikku keelt CalendarView
komponent . See toimib hästi ja pakub mis tahes kalendrikomponentidelt oodatavat minimaalset funktsionaalsust, kuvades terve kuu ja tõstes esile praeguse päeva. Mõni võib öelda, et see näeb ka hea välja, kuid ainult siis, kui kavatsete oma loomuliku ilme saada ja teil pole huvi selle väljanägemise kohandamiseks.
Näiteks CalendarView
komponent ei võimalda muuta seda, kuidas teatud päeva tähistatakse või millist taustavärvi kasutada. Samuti ei saa kuidagi lisada kohandatud teksti ega graafikat, näiteks mõne erilise sündmuse tähistamiseks. Lühidalt öeldes näeb komponent välja selline ja peaaegu midagi ei saa muuta:
õppige c-programmeerimist algajatele
CalendarView
aastal AppCompact.Light
teema.
Kuidas siis oma kalendrivaadet luua? Mõni ülaltoodud lähenemisviis toimiks. Kuid praktilisus välistab tavaliselt kolmanda võimaluse (2D graafika) ja jätab meile kaks muud meetodit ning selles artiklis kasutame mõlema segu.
Järgmiseks leiate lähtekoodi siin .
Kõigepealt alustame komponendi väljanägemisega. Asja lihtsuse huvides kuvame päevad ruudustikus ja ülaosas kuu nime koos nuppudega „järgmine kuu” ja „eelmine kuu”.
Kohandatud kalendrivaade.
See paigutus on failis control_calendar.xml
määratletud järgmiselt. Pange tähele, et mõnda korduvat märgistust on lühendatud ...
... Repeat for MON - SAT.
Eelmise paigutuse saab lisada sellisena, nagu see on Activity
või a Fragment
ja see töötab hästi. Kuid selle kapseldamine eraldiseisva kasutajaliidese komponendina hoiab ära koodi kordumise ja võimaldab moodulikujundust, kus iga moodul kannab ühte vastutust.
Meie kasutajaliidese komponent on LinearLayout
, mis sobib XML-paigutusfaili juure. Pange tähele, et koodist kuvatakse ainult olulised osad. Komponendi rakendamine asub CalendarView.java
public class CalendarView extends LinearLayout { // internal components private LinearLayout header; private ImageView btnPrev; private ImageView btnNext; private TextView txtDate; private GridView grid; public CalendarView(Context context) { super(context); initControl(context); } /** * Load component XML layout */ private void initControl(Context context) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(R.layout.control_calendar, this); // layout is inflated, assign local variables to components header = (LinearLayout)findViewById(R.id.calendar_header); btnPrev = (ImageView)findViewById(R.id.calendar_prev_button); btnNext = (ImageView)findViewById(R.id.calendar_next_button); txtDate = (TextView)findViewById(R.id.calendar_date_display); grid = (GridView)findViewById(R.id.calendar_grid); } }
Kood on üsna lihtne. Pärast loomist suurendab komponent XML-i paigutust ja kui see on tehtud, määrab ta sisemised juhtelemendid kohalikele muutujatele, et neid hiljem hõlpsamini juurde pääseda.
Selle komponendi reaalseks käitumiseks kalendrivaates on mõni äriloogika korras. Esialgu võib see tunduda keeruline, kuid tegelikult pole sellest palju. Jaotame selle:
Kalendrivaade on seitse päeva lai ja on garanteeritud, et kõik kuud algavad kusagil esimeses reas.
Kõigepealt peame välja selgitama, millisel positsioonil kuu algab, seejärel täitma kõik enne seda asetsevad positsioonid eelmise kuu numbritega (30, 29, 28 .. jne), kuni jõuame 0-ni.
Seejärel täidame jooksva kuu päevad (1, 2, 3 ... jne).
Pärast seda tulevad järgmise kuu päevad (jällegi 1, 2, 3 jne), kuid seekord täidame allesjäänud kohad ainult ruudustiku viimases reas.
Järgmine diagramm illustreerib neid samme:
Kohandatud kalendrivaate äriloogika.
Ruudustiku laiuseks on juba määratud seitse lahtrit, mis tähistab nädalakalendrit, aga kuidas oleks kõrgusega? Võrgu suurima suuruse saab määrata halvima stsenaariumi korral, kui laupäevast algab 31-päevane kuu, mis on esimese rea viimane lahter ja mille täielikuks kuvamiseks on vaja veel 5 rida. Seega piisab kõigi juhtumite käsitlemiseks kalendri seadistamisest kuue rea (kokku 42 päeva) kuvamiseks.
Kuid kõigil kuudel pole 31 päeva! Sellest tulenevaid tüsistusi saame vältida, kasutades Androidi sisseehitatud kuupäevafunktsionaalsust, vältides vajadust ise päevade arvu välja selgitada.
Nagu varem mainitud, on kuupäevafunktsionaalsused, mida pakub Calendar
klass muudab rakendamise üsna lihtsaks. Meie komponendis on updateCalendar()
Funktsioon rakendab seda loogikat:
private void updateCalendar() { ArrayList cells = new ArrayList(); Calendar calendar = (Calendar)currentDate.clone(); // determine the cell for current month's beginning calendar.set(Calendar.DAY_OF_MONTH, 1); int monthBeginningCell = calendar.get(Calendar.DAY_OF_WEEK) - 1; // move calendar backwards to the beginning of the week calendar.add(Calendar.DAY_OF_MONTH, -monthBeginningCell); // fill cells (42 days calendar as per our business logic) while (cells.size() 4. Kohandatav südames
Kuna üksikute päevade kuvamise eest vastutav komponent on GridView
, on päevade kuvamise kohandamiseks hea koht Adapter
, kuna see vastutab üksikute võrgurakkude andmete hoidmise ja vaadete suurendamise eest.
Selle näite jaoks vajame meie CalendearView
-lt järgmist:
- Praegune päev peaks olemapaks sinine tekst.
- Päevad väljaspool jooksvat kuud peaksid olemahallitas välja.
- Sündmusega päevadel peaks olema kuvatud spetsiaalne ikoon.
- Kalendri päis peaks värve muutma sõltuvalt aastaajast (suvi, sügis, talv, kevad).
Esimesi kolme nõuet on teksti atribuutide ja taustressursside muutmisega lihtne saavutada. Rakendame CalendarAdapter
selle ülesande täitmiseks. See on piisavalt lihtne, et see võib olla CalendarView
liikmeklass. Alistades getView()
funktsiooni, saame saavutada ülaltoodud nõuded:
@Override public View getView(int position, View view, ViewGroup parent) { // day in question Date date = getItem(position); // today Date today = new Date(); // inflate item if it does not exist yet if (view == null) view = inflater.inflate(R.layout.control_calendar_day, parent, false); // if this day has an event, specify event image view.setBackgroundResource(eventDays.contains(date)) ? R.drawable.reminder : 0); // clear styling view.setTypeface(null, Typeface.NORMAL); view.setTextColor(Color.BLACK); if (date.getMonth() != today.getMonth() || date.getYear() != today.getYear()) { // if this day is outside current month, grey it out view.setTextColor(getResources().getColor(R.color.greyed_out)); } else if (date.getDate() == today.getDate()) { // if it is today, set it to blue/bold view.setTypeface(null, Typeface.BOLD); view.setTextColor(getResources().getColor(R.color.today)); } // set text view.setText(String.valueOf(date.getDate())); return view; }
Lõplik disaininõue võtab natuke rohkem tööd. Kõigepealt lisame värvid neljaks hooajaks /res/values/colors.xml
#44eebd82 #44d8d27e #44a1c1da #448da64b
Seejärel määragem massiivi iga kuu aastaaja määramiseks (eeldades, et põhjapoolkera on lihtsuse mõttes; vabandust Austraaliast!). Aastal CalendarView
lisame järgmised liikme muutujad:
// seasons' rainbow int[] rainbow = new int[] { R.color.summer, R.color.fall, R.color.winter, R.color.spring }; int[] monthSeason = new int[] {2, 2, 3, 3, 3, 0, 0, 0, 1, 1, 1, 2};
Sel viisil valitakse sobiv värv, valides sobiva aastaaja (monthSeason[currentMonth]
) ja valides seejärel vastava värvi (rainbow[monthSeason[currentMonth]
), see lisatakse updateCalendar()
veendumaks, et kalendri muutmisel on valitud sobiv värv.
c++ kokkupõrke tuvastamine
// set header color according to current season int month = currentDate.get(Calendar.MONTH); int season = monthSeason[month]; int color = rainbow[season]; header.setBackgroundColor(getResources().getColor(color));
Sellega saame järgmise tulemuse:
Päise värv muutub vastavalt aastaajale.
Tähtis märkus tee tõttu HashSet
võrdleb objekte, ülaltoodud kontroll eventDays.contains(date)
aastal updateCalendar()
ei anna kuupäevaobjektide puhul tõde, kui need pole täpselt identsed. See ei tee Date
jaoks erikontrolli andmetüüp. Selle vältimiseks asendatakse see kontroll järgmise koodiga:
for (Date eventDate : eventDays) { if (eventDate.getDate() == date.getDate() && eventDate.getMonth() == date.getMonth() && eventDate.getYear() == date.getYear()) { // mark this day for event view.setBackgroundResource(R.drawable.reminder); break; } }
5. See näeb disainiajal kole välja
Androidi valik kohatäidete jaoks disainiajal võib olla küsitav. Õnneks Android kohe installeerib meie komponendi, et see kasutajaliidese kujundajana renderdada, ja saame seda ära kasutada, helistades updateCalendar()
komponentkonstruktoris. Nii on komponendil projekteerimisajal tegelikult mõtet.

Kui komponendi lähtestamine nõuab palju töötlemist või laadib palju andmeid, võib see mõjutada IDE toimivust. Sellisel juhul pakub Android suurepärast funktsiooni nimega isInEditMode()
mida saab kasutada kasutatavate andmete hulga piiramiseks, kui komponent on kasutajaliidese disaineris tegelikult instantsitud. Näiteks kui CalendarView
-sse laaditavaid sündmusi on palju, võime kasutada isInEditMode()
updateCalendar()
sees funktsioon tühja / piiratud sündmuste loendi loomiseks kujundusrežiimis ja muidu reaalse laadimine.
6. Komponendi kutsumine
Komponendi saab lisada XML-i paigutusfailidesse (näidiskasutuse leiate jaotisest activity_main.xml
):
HashSet events = new HashSet(); events.add(new Date()); CalendarView cv = ((CalendarView)findViewById(R.id.calendar_view)); cv.updateCalendar(events);
Ja laaditakse suhtlemiseks pärast paigutuse laadimist:
HashSet
Ülaltoodud kood loob CalendarView
sündmustest, lisab sellele praeguse päeva ja edastab selle seejärel CalendarView
Selle tulemusena on CalendarView
kuvab praeguse päeva rasvase sinisega ja paneb sellele ka sündmuse marker:
CalendarView
sündmuse kuvamine
7. Atribuutide lisamine
Teine Androidi pakutav võimalus on kohandatud komponendile atribuutide määramine. See lubab Androidi arendajad komponendi kasutamine seadete valimiseks paigutuse XML-i kaudu ja tulemuse nägemiseks kohe kasutajaliidese kujunduses, selle asemel, et oodata ja vaadata, kuidas dateFormat
näeb välja nagu tööajal. Lisame võimaluse muuta komponendi kuupäevavormingu kuvamist, näiteks kolmetähelise lühendi asemel kirjutada kuu täisnimi.
hea andmebaasi disain ei sisalda:
Selleks on vaja järgmisi samme:
- Deklareerige atribuut. Nimetagem seda
string
ja anna see /res/values/attrs.xml
andmetüüp. Lisage see kausta 'MMMM yyyy'
:
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CalendarView); dateFormat = ta.getString(R.styleable.CalendarView_dateFormat);
- Kasutage komponenti kasutavas paigutuses atribuuti ja andke sellele väärtus
CalendarView
Fragment
- Lõpuks laske komponendil kasutada atribuudi väärtust:
Activity
] Ehitage projekt ja märkate kuvatud kuupäeva muudatusi UI disainer kasutada kuu täisnime, näiteks „juuli 2015”. Proovige pakkuda erinevaid väärtusi ja vaadake, mis juhtub.
// long-pressing a day grid.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView view, View cell, int position, long id) { // handle long-press if (eventHandler == null) return false; Date date = view.getItemAtPosition(position); eventHandler.onDayLongPress(date); return true; } });
Muutmine atribuudid.
8. Komponendiga suhtlemine
Kas olete proovinud konkreetsel päeval vajutada? Meie komponendi sisemised kasutajaliidese elemendid käituvad endiselt tavapärasel eeldataval viisil ja käivitavad sündmused vastuseks kasutaja toimingutele. Niisiis, kuidas me nende sündmustega hakkama saame?
Vastus hõlmab kahte osa:
- Jäädvustage komponendi sisesed sündmused ja
- Teata sündmustest komponendi vanemale (võib olla
eventHandler
, CalendarView
või isegi mõni muu komponent).
Esimene osa on üsna sirgjooneline. Näiteks pika vajutusega ruudustikuüksuste käsitlemiseks määrame oma komponendiklassi vastava kuulaja:
public interface EventHandler { void onDayLongPress(Date date); }
Sündmustest teatamiseks on mitu meetodit. Otsene ja lihtne on kopeerida see, kuidas Android seda teeb: see pakub komponendi sündmustele liidese, mida komponendi vanem rakendab (setEventHandler()
ülaltoodud koodijupis).
Liidese funktsioone saab edastada mis tahes rakendusega seotud andmetega. Meie puhul tuleb liidesel paljastada üks sündmuste käitleja, millele antakse üle pressitud päeva kuupäev. Järgmine liides on määratletud jaotises @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); HashSet events = new HashSet(); events.add(new Date()); CalendarView cv = ((CalendarView)findViewById(R.id.calendar_view)); cv.updateCalendar(events); // assign event handler cv.setEventHandler(new CalendarView.EventHandler() { @Override public void onDayLongPress(Date date) { // show returned day DateFormat df = SimpleDateFormat.getDateInstance(); Toast.makeText(MainActivity.this, df.format(date), LENGTH_SHORT).show(); } }); }
GridView
Vanemate pakutava rakenduse saab kalendrivaate esitada onDayLongPress()
kaudu. Siin on näidiskasutus saidilt „MainActivity.java”:
Intents
Päeva pikalt vajutamine vallandab pika pressi sündmuse, mille jäädvustab ja haldab BroadcastReceivers
ja teatati helistades Activity
pakutavas rakenduses, mis omakorda näitab ekraanil vajutatud päeva kuupäeva:

Teine, täpsem viis selle lahendamiseks on Androidi kasutamine Service
ja Activity
. See on eriti kasulik, kui kalendri sündmusest tuleb teavitada mitut komponenti. Näiteks kui kalendris ühe päeva vajutamine nõuab teksti kuvamist EventHandler
-s ja taustal allalaaditav fail Service
.
Eelmise lähenemise kasutamine nõuab Intent
esitada Activity
komponendile, sündmuse käitlemine ja seejärel selle edastamine Service
Selle asemel, kui komponent edastab BroadcastReceivers
ja mõlemad Activity
ja Service
aktsepteerides seda omaenda kaudu isInEditMode()
mitte ainult ei hõlbusta elu, vaid aitab ka
|_+_|
lahutada ja |_+_|
kõnealune. Järeldus
Vaadake Androidi kohandamise suurepärast jõudu! Piiksuma Nii saate oma kohandatud komponendi luua järgmiselt.
- Looge XML-i paigutus ja kujundage see vastavalt oma vajadustele.
- Tuletage oma komponentide klass sobivast vanemkomponendist vastavalt oma XML-paigutusele.
- Lisage oma komponendi äriloogika.
- Kasutage atribuute, et võimaldada kasutajatel komponendi käitumist muuta.
- Kasutajaliidese kujundaja komponendi kasutamise hõlbustamiseks kasutage Androidi
|_+_|
funktsioon.
Selles artiklis lõime näitena kalendrivaate peamiselt seetõttu, et aktsiakalendri vaade on paljuski puudulik. Kuid te pole mingil viisil piiratud selles, milliseid komponente saate luua. Sama tehnika abil saate luua kõike vajalikku, taevas on piir!
Tänan teid selle juhendi lugemise eest, soovin teile õnne kodeerimisel!