Vuorovaikutteisen mukautetun kaaviowidgetin rakentaminen
Yhdistä CustomPainter ja eleentunnistus kosketukseen reagoivan datakaavion piirtämiseksi.
Vuorovaikutteisen mukautetun kaaviowidgetin rakentaminen on ilmainen Mobiilikehitys Flutterilla-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Mobiilikehitys Flutterilla-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Mobiilikehitys Flutterilla-kurssilla on yhteensä 4 oppituntia.
Miksi interaktiivinen mukautettu kaavio?
Flutterissa ei ole valmista kaaviowidgetiä. Kun tarvitsette kosketukseen reagoivan pylväs- tai viivakaavion, joka vastaa tarkasti suunnitteluanne, yhdistätte kaksi primitiiviä:
- CustomPainter — piirtää kaavion
Canvas-alustalle. - GestureDetector — tunnistaa napautukset ja vedot, jotta käyttäjä voi korostaa tai tarkastella datapisteitä.
Tässä oppitunnissa rakennamme pylväskaavion, joka korostaa käyttäjän koskettamaa pylvästä ja ilmoittaa sen arvon. Keskeinen ajatus on, että painter on tilan puhdas funktio ja eleet muuttavat tuota tilaa.
Tietomalli
Aloittakaa yksinkertaisesta muuttumattomasta mallista. Kun se ei riipu kehyksestä, sitä on helppo testata ja käsitellä. Jokaisella pylväällä on label ja value.
Tämä koodiesimerkki on puhdasta Dartia ilman Flutter-tuonteja, joten se toimii itsenäisesti.
class Bar {
final String label;
final double value;
const Bar(this.label, this.value);
}
void main() {
final data = <Bar>[
const Bar('Mon', 12),
const Bar('Tue', 30),
const Bar('Wed', 8),
const Bar('Thu', 22),
];
final maxValue = data.map((b) => b.value).reduce((a, b) => a > b ? a : b);
print('Bars: ${data.length}, max value: $maxValue');
for (final b in data) {
final ratio = (b.value / maxValue * 100).toStringAsFixed(0);
print('${b.label}: $ratio% of tallest');
}
}CustomPainterin runko
CustomPainter toteuttaa kaksi metodia:
paint(Canvas canvas, Size size)— tässä suoritatte piirtämisen.shouldRepaint(old)— palauttakaatrue, kun syötteet ovat muuttuneet, jotta Flutter piirtää näkymän uudelleen.
Välittäkää data ja mahdollinen vuorovaikutustila, kuten korostetun pylvään indeksi, painterin konstruktorille final-kenttinä.
class BarChartPainter extends CustomPainter {
final List<Bar> bars;
final int? highlightedIndex;
BarChartPainter({required this.bars, this.highlightedIndex});
@override
void paint(Canvas canvas, Size size) {
// drawing logic goes here
}
@override
bool shouldRepaint(covariant BarChartPainter old) {
return old.bars != bars || old.highlightedIndex != highlightedIndex;
}
}Pylväiden geometrian laskeminen
Muuntakaa jokainen data-arvo pikselikoordinaateiksi ennen piirtämistä. Jakakaa Canvasin size-arvon perusteella leveys yhtä suuriin paikkoihin ja suhteuttakaa korkeudet suurimpaan arvoon.
Kun tallennatte kunkin pylvään Rect-arvon, voitte käyttää täsmälleen samaa geometriaa myöhemmin osumatestaukseen — piirtämisen ja eleiden on vastattava toisiaan.
List<Rect> computeBarRects(List<Bar> bars, Size size) {
final maxValue = bars.map((b) => b.value).reduce((a, b) => a > b ? a : b);
final slotWidth = size.width / bars.length;
const barFraction = 0.6; // bars take 60% of their slot
final rects = <Rect>[];
for (var i = 0; i < bars.length; i++) {
final barWidth = slotWidth * barFraction;
final left = i * slotWidth + (slotWidth - barWidth) / 2;
final height = (bars[i].value / maxValue) * size.height;
final top = size.height - height;
rects.add(Rect.fromLTWH(left, top, barWidth, height));
}
return rects;
}Pylväiden piirtäminen
Luokaa paint-metodissa Paint-olio ja kutsukaa jokaiselle pylväälle canvas.drawRect-metodia. Antakaa kosketetulle pylväälle erottuva väri käyttämällä highlightedIndex-arvoa.
Vinkki: luokaa Paint-oliot silmukan ulkopuolella kerran, jos niiden ominaisuudet eivät muutu, ja vaihtakaa vain color-arvoa pylväskohtaisesti.
@override
void paint(Canvas canvas, Size size) {
final rects = computeBarRects(bars, size);
final paint = Paint()..style = PaintingStyle.fill;
for (var i = 0; i < rects.length; i++) {
paint.color = (i == highlightedIndex)
? const Color(0xFFFF7043) // highlighted
: const Color(0xFF42A5F5); // default
final rounded = RRect.fromRectAndRadius(
rects[i],
const Radius.circular(4),
);
canvas.drawRRect(rounded, paint);
}
}Selitteiden piirtäminen TextPainterilla
Canvas ei voi piirtää tekstiä suoraan — käyttäkää TextPainter-oliota. Asetelkaa teksti ensin ja kutsukaa sitten paint-metodia haluamassanne kohdassa. Keskittäkää kukin selite pylvään alle.
void drawLabel(Canvas canvas, String text, Offset center) {
final tp = TextPainter(
text: TextSpan(
text: text,
style: const TextStyle(color: Color(0xFF333333), fontSize: 12),
),
textDirection: TextDirection.ltr,
)..layout();
final offset = Offset(center.dx - tp.width / 2, center.dy);
tp.paint(canvas, offset);
}Painterin sijoittaminen widgetiin
Ympäröikää painter CustomPaint-widgetillä. Antakaa sille size (tai antakaa sen laajentua), jotta sillä on piirrettävä alue.
Koska korostus on vuorovaikutustila, isäntä on StatefulWidget, joka säilyttää _highlightedIndex-arvon ja rakentaa näkymän uudelleen sen muuttuessa.
class BarChart extends StatefulWidget {
final List<Bar> bars;
const BarChart({super.key, required this.bars});
@override
State<BarChart> createState() => _BarChartState();
}
class _BarChartState extends State<BarChart> {
int? _highlightedIndex;
@override
Widget build(BuildContext context) {
return CustomPaint(
size: const Size(double.infinity, 200),
painter: BarChartPainter(
bars: widget.bars,
highlightedIndex: _highlightedIndex,
),
);
}
}Napautuksen osumatestaus
Selvittääksesi, mitä palkkia kosketettiin, laske samat suorakulmiot uudelleen ja tarkista, mikä niistä sisältää kosketuspisteen. Puhdas apufunktio pitää tämän logiikan testattavana ja identtisenä piirtäjän piirtämän kanssa.
Tämä katkelma on itsenäinen Dart-koodi — se mallintaa suorakulmiota ja samaa osumatestauksen matematiikkaa, jota widget käyttää.
class Box {
final double left, top, width, height;
const Box(this.left, this.top, this.width, this.height);
bool contains(double x, double y) =>
x >= left && x <= left + width && y >= top && y <= top + height;
}
int? hitTest(List<Box> boxes, double x, double y) {
for (var i = 0; i < boxes.length; i++) {
if (boxes[i].contains(x, y)) return i;
}
return null;
}
void main() {
final boxes = [
const Box(0, 100, 40, 100),
const Box(60, 50, 40, 150),
const Box(120, 120, 40, 80),
];
print(hitTest(boxes, 70, 90)); // 1
print(hitTest(boxes, 200, 10)); // null
}GestureDetectorin käyttöönotto
Ympäröi CustomPaint komponentilla GestureDetector. Lue onTapDown-tapahtumassa kosketuksen paikallinen sijainti, suorita osumatestaus ja päivitä korostus kutsumalla setState-metodia.
Käytä details.localPosition-arvoa (joka on jo suhteessa widgetiin), älä globaalia sijaintia.
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapDown: (details) {
final size = context.size!;
final rects = computeBarRects(widget.bars, size);
final p = details.localPosition;
int? hit;
for (var i = 0; i < rects.length; i++) {
if (rects[i].contains(p)) { hit = i; break; }
}
setState(() => _highlightedIndex = hit);
},
child: CustomPaint(
size: const Size(double.infinity, 200),
painter: BarChartPainter(
bars: widget.bars,
highlightedIndex: _highlightedIndex,
),
),
);
}Vastaaminen vetä eleisiin
Jos haluat pyyhkäisyä tukevan käyttökokemuksen (sormea vedetään palkkien yli niiden tarkastelemiseksi), käsittele onPanUpdate-tapahtumaa onTapDown-tapahtuman lisäksi. Sama osumatestaus suoritetaan jatkuvasti sormen liikkuessa.
Sijoita korostuksen päivitys apufunktioon, jotta napautus ja veto käyttävät samaa koodipolkua.
void _updateHighlight(Offset local) {
final size = context.size!;
final rects = computeBarRects(widget.bars, size);
int? hit;
for (var i = 0; i < rects.length; i++) {
if (rects[i].contains(local)) { hit = i; break; }
}
if (hit != _highlightedIndex) {
setState(() => _highlightedIndex = hit);
}
}
// in build():
// onTapDown: (d) => _updateHighlight(d.localPosition),
// onPanUpdate: (d) => _updateHighlight(d.localPosition),Valitun arvon näyttäminen
Lisätään nyt palaute. Piirrä kaavion alle Text, joka näyttää korostetun palkin tiedot, tai piirrä valitun palkin yläpuolelle työkaluvihje kankaalle.
- Pidä piirtäjä käyttöliittymän tekstin suhteen tilattomana — välitä sille vain korostetun palkin indeksi.
- Vältä raskaita toimintoja
paint-metodissa; laske geometria etukäteen ja käytä sitä uudelleen sekä piirtämiseen että osumatestaukseen. - Määritä
shouldRepainttäsmällisesti, jotta et piirrä kaikkea uudelleen jokaisella ruudulla.
Widget _selectionLabel() {
if (_highlightedIndex == null) {
return const Text('Tap a bar to inspect');
}
final bar = widget.bars[_highlightedIndex!];
return Text('${bar.label}: ${bar.value.toStringAsFixed(1)}',
style: const TextStyle(fontWeight: FontWeight.bold));
}Pikatarkistus
Testaa, miten hyvin ymmärrät piirtämisen ja eleiden käsittelyn johdonmukaisuuden.
Kertaus
Rakensit kosketukseen reagoivan kaavion erottamalla vastuualueet:
- Datamalli — yksinkertainen, muuttumaton ja testattava.
- Geometria-apufunktio — yksi funktio muuntaa arvot
Rect-arvoiksi, joita käytetään sekä piirtämisessä että osumatestauksessa. - CustomPainter — piirtää palkit ja selitteet datan ja korostetun indeksin perusteella sekä käyttää täsmällistä
shouldRepaint-toteutusta. - StatefulWidget — säilyttää vuorovaikutustilan ja kutsuu
setState-metodia. - GestureDetector —
onTapDownjaonPanUpdatesuorittavat jaetun osumatestauksenlocalPosition-arvon perusteella.
Kultainen sääntö: pidä piirtäjä tilan puhtaana funktiona ja anna eleiden olla ainoa asia, joka muuttaa tätä tilaa.
Opi Dart tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 22
- Oppitunnit
- 88
Usein kysytyt kysymykset
Onko oppitunti ”Vuorovaikutteisen mukautetun kaaviowidgetin rakentaminen” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Mobiilikehitys Flutterilla-oppimispolun 3 oppituntia, myös oppitunnin “Vuorovaikutteisen mukautetun kaaviowidgetin rakentaminen”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Mobiilikehitys Flutterilla-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Vuorovaikutteisen mukautetun kaaviowidgetin rakentaminen”?
Yhdistä CustomPainter ja eleentunnistus kosketukseen reagoivan datakaavion piirtämiseksi. Harjoittelet Mobiilikehitys Flutterilla-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Mobiilikehitys Flutterilla-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Mobiilikehitys Flutterilla-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.
Kuinka kauan ”Vuorovaikutteisen mukautetun kaaviowidgetin rakentaminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Mobiilikehitys Flutterilla-oppitunnilla?
Kyllä. Jokainen Mobiilikehitys Flutterilla-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Canvas API: polut, maalaus ja shaderit
- Vuorovaikutteisen mukautetun kaaviowidgetin rakentaminen
- Clipping, blend-tilat ja tasojen koostaminen
- Hit testing ja uudelleenpiirron optimointi