Ad

Flutter Random Image.asset Changes On Hovering Button?

- 1 answer

I want to show a random picture everytime the user enters the page. I also have a Button (the red container with hovering) on this page, and when the user is hovering it, a new random picture shows, but it shouldn't change since the page was loaded. I think it has something to do with the setState(), but I don't know what to do. Code:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:core';
import 'dart:math';


class Home2 extends StatefulWidget {
  const Home2({Key? key}) : super(key: key);

  @override
  _Home2State createState() => _Home2State();
}

class _Home2State extends State<Home2> {
  dynamic listCinematicImages = [
    "assets/cinematic/1.jpg",
    "assets/cinematic/2.jpg",
    "assets/cinematic/3.jpg",
    "assets/cinematic/4.jpg",
    "assets/cinematic/5.jpg",
    "assets/cinematic/6.jpg",
    "assets/cinematic/7.jpg",
  ];
  late Random rnd;

  @override
  
  bool isHoveringButton = false;
  
  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Scaffold(
      backgroundColor: Colors.black,
      body: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Container(
            height: double.infinity,
            width: size.width * 0.5,
            alignment: Alignment.center,
            child: InkWell(
              onTap: () {

              },
              onHover: (hovering) {
                setState(() => isHoveringButton = hovering);
              },
              child: Container(
                height: 50,
                width: 50,
                color: Colors.red,
              ),
            ),
          ),
          Container(
            height: double.infinity,
            width: size.width * 0.5,
            child: img(),
          ),
        ],
      ),
    );
  }

  Image img() {
    int min = 0;
    int max = listCinematicImages.length-1;
    rnd = new Random();
    int r = min + rnd.nextInt(max - min);
    String image_name  = listCinematicImages[r].toString();
    return Image.asset(image_name, fit: BoxFit.cover,);
  }
}

I dont know if this helps but this is some error given out:

Error: Expected a value of type 'Map<String, dynamic>', but got one of type 'Null'
    at Object.throw_ [as throw] (http://localhost:60569/dart_sdk.js:5054:11)
    at Object.castError (http://localhost:60569/dart_sdk.js:5013:15)
    at Object.cast [as as] (http://localhost:60569/dart_sdk.js:5336:17)
    at Function.as_C [as as] (http://localhost:60569/dart_sdk.js:4959:19)
Ad

Answer

alright there's a lot a things going on here. Let's think about this step by step. You're trying to show a new image on certain events. So we need to create a variable to keep track of the current image:

class Home2 extends StatefulWidget {
  const Home2({Key? key}) : super(key: key);

  @override
  _Home2State createState() => _Home2State();
}

class _Home2State extends State<Home2> {
  static const listCinematicImages = [
    "assets/cinematic/1.jpg",
    "assets/cinematic/2.jpg",
    "assets/cinematic/3.jpg",
    "assets/cinematic/4.jpg",
    "assets/cinematic/5.jpg",
    "assets/cinematic/6.jpg",
    "assets/cinematic/7.jpg",
  ];

 late String currentImage;
    
}

before we start worrying about the events, let's figure out how to select a random image from your list. the function you provided has the right elements but there's some funky stuff going on. a simple example I'd give is:

String _getRandomImage() {
  final randomIndex = Random().nextInt(listCinematicImages.length-1);
  return listCinematicImages[randomIndex];
}

now we have all the elements, we just have to update the widget at the correct time. firstly you want to set a new image every time this widget is loaded. we can do this using the initState method:

@override
void initState() {
  super.initState();

  final newImage = _getRandomImage();
  setState(() => currentImage = newImage);
}

and you want to change the image again when a user hovers over the image. You can indeed do this with an InkWell but keep in mind according to the documentation the onHover will provide a callback every time a mouse enters AND leaves the region, so we have to make sure to only update the image when we enter the region:

InkWell(
  onHover: (bool hasEntered) {
    if(!hasEntered) return;
    
    final newImage = _getRandomImage();
    setState(() => currentImage = newImage);
  }
);

And that's it! to put it all together with your example:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:core';
import 'dart:math';


class Home2 extends StatefulWidget {
  const Home2({Key? key}) : super(key: key);

  @override
  _Home2State createState() => _Home2State();
}

class _Home2State extends State<Home2> {
  static const listCinematicImages = [
    "assets/cinematic/1.jpg",
    "assets/cinematic/2.jpg",
    "assets/cinematic/3.jpg",
    "assets/cinematic/4.jpg",
    "assets/cinematic/5.jpg",
    "assets/cinematic/6.jpg",
    "assets/cinematic/7.jpg",
  ];

  late String currentImage;

  @override
  void initState() {
    super.initState();

    final newImage = _getRandomImage();
    setState(() => currentImage = newImage);
  }


  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Scaffold(
      backgroundColor: Colors.black,
      body: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Container(
            height: double.infinity,
            width: size.width * 0.5,
            alignment: Alignment.center,
            child: InkWell(
              onHover: (bool hasEntered) {
                if(!hasEntered) return;

                final newImage = _getRandomImage();
                setState(() => currentImage = newImage);
              },
              child: Container(
                height: 50,
                width: 50,
                color: Colors.red,
              ),
            ),
          ),
          Container(
            height: double.infinity,
            width: size.width * 0.5,
            child: Image.asset(currentImage, fit: BoxFit.cover,);,
          ),
        ],
      ),
    );
  }

  String _getRandomImage() {
    final randomIndex = Random().nextInt(listCinematicImages.length-1);
    return listCinematicImages[randomIndex];
  }
}

Ad
source: stackoverflow.com
Ad