Note
This article was automatically translated using Google
**Shout out! **If you want to do partial refresh through routing, you must write the routing yourself, don’t use the one that comes with flutter, it will make you feel crashed. Today, I switched to the global routing for the local refresh on the right side. After changing most of the code, I found that it was impossible to dynamically refresh while keeping the left and bottom Widget. I rewrote it in a fit of anger and it finally worked. But it wasted a long time. There is no way, in order to adjust the mobile terminal at that time, the left side can be used as a side-sliding window independently, decided to use ValueNotifier to hard-write the route, and then remove the current page highlight on the left side, mainly Although the Detail page can be tracked to the superior, it doesn’t matter if you want it or not. I wrote a huge 40 point headline and put it there, so I can’t miss it
At present, it can be used. The singer, album and all the logic of playing have been completed. There is also the home page after that. It is nothing more than a convenient use such as query point is playing. There are two more important points, search and lyrics. I don’t know if direct transcoding can realize complex and simple search. If not, you need to use API, which will waste query time
1. Album Waterfall
This is what I have always wanted. Since I used Jellyfin, I feel that I have watched movies for nothing before. This kind of TV curtain wall is more handsome. Waterfall has ready-made wheels that can be used [flutter_staggered_grid_view](https://pub.dev /packages/flutter_staggered_grid_view) is very simple to implement, just add it in pubspec.yaml
and then flutter pub get
It itself supports a variety of presentation methods, you can go to the homepage for details, but I chose MasonryGridView
, which is most suitable for a large number of pictures. It is the same as building a ListView. There are three attributes that need to be defined here.
crossAxisCount: How many columns
mainAxisSpacing: line spacing
crossAxisSpacing: Column spacing
I suggest doing a calculation, because if you fix Count, it will cause a problem. Dragging the form will make the picture very large, which is very strange
1 | //Get the window size |
In this way, how do you drag the form? The width of the picture will only change in a small range, it will not be particularly exaggerated, and the construction is also very simple.
1 | MasonryGridView.count( |
You can seal a combination of Widget inside, such as adding two lines of text to a picture, and the effect will come out
Of course, you can do image caching. I wanted to do it at first, but I just didn’t know whether to save it in a folder or convert it to base64 and save it in the database.
In fact, it’s okay to not do caching, and the effect of lazy loading of pictures is still possible. Use frameBuilder to achieve the fade-in effect
1 | ClipRRect( |
2. Music playback
Playing a song is very simple, just setAudioSource
, the trouble is the playlist, and the button operation to control the playlist. For example, the previous song is gone, but if the button is not grayed out, an error will be reported. All controls are performed using ValueNotifier
. I understand it.
2.1. Set monitoring variables
1 | //Monitor the current resource ID. This is not only used for music playback, but also for obtaining singer pictures. |
2.2. Triggering
After clicking the song in the song list, pass the id, song List and the index of the current song in the list, and then seal a Map
The main purpose is to get the picture URL of the song. This is not in the original Map. You need to go to the background to create a URL with the server address and identity information. Otherwise, it is more convenient to use the Songs instance directly.
1 | onTap: () async { |
2.3. Receive and generate playlist
What is received here is activeSongValue
, why not use activeList
directly, because if you receive activeList
, click other songs in the current list, and its default value will not change
1 | ValueListenableBuilder<String>( |
If it is the default value 1, it means that you have not selected music
When the value changes, start generating the playlist
1 | Future<void> setAudioSource() async { |
2.4. Monitor playback changes
When playing the next song, you need to replace the information of the song name and cover. At this time, you need to inject monitoring to operate
Just Audio has a number of different event streams, all of which can be listened to:
- sequenceStream: This is the playlist in the order it was added, whenever the playlist changes, a new list will be generated here
- shuffleModeEnabledStream: ShuffleModeEnabledStream listener, open and close this mode, is a Boolean value
- shuffleIndicesStream: This is a list of shuffle integers pointing to the
sequenceStream
of items in the playlist (it does not shuffle itself).shuffle
When this method is called on the audio player, a new list will be generated here. - currentIndexStream: This stream notifies the index of the current song when the song first starts. This integer points to an audio source
sequenceStream
in the playlist - loopModeStream:By default all songs in the list are played at once. However, you can also choose to repeat a single song or even a playlist, which is the loop mode,
LoopMode
This stream will generate a new value every time the loop mode changes
Well, just look at the above. For monitoring, you can do it with one, that is, sequenceStateStream. Here, as long as one of the above five streams generates a new value, sequenceStateStream
will generate a combined value type SequenceState
, one top five, happy
First add this method call in initState, then..
1 | void _listenForChangesInSequenceState() { |
2.5. Fast Forward and Fast Rewind
In fact, many people have canceled these two buttons now, because there is a progress bar, that is so convenient, but I have written the buttons before, so I will write them, it is a pity to delete them
1 | IconButton( |
Here you need to make a judgment. If your current position minus the position you want to cancel is less than 0, don’t operate to avoid error reporting. It doesn’t matter if you move forward.
2.6. Head up and down
Here you need to monitor the previously set values of isFirstSongNotifier and isLastSongNotifier. If you don’t filter, click on the first song when playing the first song, and click on the next song when you are playing the last song. there will be problems
1 | ValueListenableBuilder<bool>( |
Make a judgment, if there is a problem, just gray the button, and then pass a null in onPressed
2.7. Single loop, all loop, random play, stop, pause
The difficulty lies in the above. After everything is written, the button part is relatively simple
Single loop:player.setLoopMode(LoopMode.one);
**Loop all: ** player.setLoopMode(LoopMode.all);
Play in random order: player.setShuffleModeEnabled(true);
3. Monospace font
Since numbers are added before and after the progress bar of the song, an old-fashioned problem arises, that is, when the number goes from 1 to 0, the progress bar behind will be displaced, so the numbers here need to use monospaced fonts.
I used two fonts for the whole APP, one is NotoSansSC, which supports Chinese, Japanese, Korean and English, and it is very happy to use. It was dragged from the backup font of Jellyfin I set at that time. At that time, it was also used to display Chinese, Japanese, Korean and English subtitles, and it can be used here as well.
However, there is a problem with this font. It has two versions. The normal version can display both numbers and English, but the Mono version, which is a monospaced font, will display English and numbers in half-width, and it will become thinner. It looks like The head is very big, so I found a small monospaced font from Google Fonts, which is specially used for the number in front of the progress bar to avoid displacement
Declare Asset
Still declared in pubspec.yaml
1 | # To add assets to your application, add an assets section, like this: |
- Topical use
1 | Text( |
- Global use
1 | return MaterialApp( |
4. Todo List
I have been playing with this thing for a week. When I am under a lot of pressure, writing code really relieves pressure, so I am not in a hurry to finish it, take it slowly
Todo List was updated directly on Github
In fact, it is already available, and those who are interested can come down and play, XiuMusic