将一个imageview的动画清零

博客主要围绕将ImageView的动画清零展开,但具体内容缺失。推测可能涉及相关技术操作,以实现清除ImageView动画的效果,属于移动开发中图像处理相关内容。
package com.weishitechsub.quanminchangKmianfei.fragment.home; import android.Manifest; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.net.Uri; import android.os.AsyncTask; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CircleCrop; import com.hfd.common.base.BaseFragment; import com.hfd.common.net.HttpBuiler; import com.hfd.common.net.JsonGenericsSerializator; import com.hfd.common.net.Url; import com.hfd.common.util.DensityUtil; import com.hfd.common.util.ToastUtil; import com.hw.lrcviewlib.LrcRow; import com.hw.lrcviewlib.LrcView; import com.weishitechsub.quanminchangKmianfei.bean.MusicBean; import com.weishitechsub.quanminchangKmianfei.dialog.PermissionDialog; import com.weishitechsub.quanminchangKmianfei.utils.MusicCache; import com.weishitechsub.quanminchangKmianfei.utils.MusicPlayerManager; import com.weishitechsub.quanminchangKmianfei.utils.PermissionUtils; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import pub.devrel.easypermissions.EasyPermissions; import com.hfd.common.net.GenericsCallback; import com.weishitechsub.quanminchangKmianfei.R; import com.weishitechsub.quanminchangKmianfei.utils.OnMultiClickListener; import okhttp3.Call; /** * 高端语音导航首页 */ public class HomeFragment extends BaseFragment implements EasyPermissions.PermissionCallbacks{ ImageView iv_song,iv_xh,iv_sys,iv_bf,iv_xys,iv_xz; TextView tv_start_time,tv_end_time,tv_no_lyric,tv_title,tv_singer; LrcView lyricView; SeekBar seekbar; private List<MusicBean.DataBean> restList = new ArrayList<>(); private List<MusicBean.DataBean> musicList; // 存储获取到的歌曲列表 private ObjectAnimator rotationAnimator; private boolean isRotating = false; // 记录当前是否正在旋转 private boolean shouldPauseWhenBackground = true; // 默认返回后台时暂停 private static final String[] PERMS_CAMERA = new String[] {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE}; // 需要请求的权限数组 private static final int RC_CAMERA_PERM = 123; // 请求码,唯一标识 private static final int REQUEST_CODE_WRITE_SETTINGS = 101; private AlertDialog progressDialog; private Handler handler; private Runnable updateProgressRunnable; @Override protected int setLayout() { return R.layout.fragment_home; } @Override protected void initView() { iv_song = fvbi(R.id.iv_song); lyricView = fvbi(R.id.lyricView); tv_start_time = fvbi(R.id.tv_start_time); seekbar = fvbi(R.id.seekbar); tv_end_time = fvbi(R.id.tv_end_time); iv_xh = fvbi(R.id.iv_xh); iv_sys = fvbi(R.id.iv_sys); iv_bf = fvbi(R.id.iv_bf); iv_xys = fvbi(R.id.iv_xys); iv_xz = fvbi(R.id.iv_xz); tv_no_lyric = fvbi(R.id.tv_no_lyric); tv_title = fvbi(R.id.tv_title); tv_singer = fvbi(R.id.tv_singer); // 设置最大值为100 seekbar.setMax(100); initLyricStyle(); // 初始化旋转动画 initRotationAnimation(); } @Override protected void initClick() { iv_xz.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { // 设置:弹权限时不暂停音乐 shouldPauseWhenBackground = false; getSavePermissions(); } }); iv_sys.setOnClickListener(v -> playPrevious()); // 上一首 iv_xys.setOnClickListener(v -> playNext()); // 下一首 iv_bf.setOnClickListener(v -> togglePlayPause()); // 播放/暂停 seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { int duration = MusicPlayerManager.getInstance().getDuration(); int newPosition = (int) ((progress / 100.0) * duration); MusicPlayerManager.getInstance().seekTo(newPosition); } } @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) {} }); } @Override protected void initData() { musicAppInfo(); } private void musicAppInfo() { HashMap<String, String> map = new HashMap<>(); showDialog(); HttpBuiler.getInfo(Url.music, map).build().execute( new GenericsCallback<MusicBean>(new JsonGenericsSerializator()) { @Override public void onError(Call call, Exception e, int id) { dissmiss(); ToastUtil.showShortToast(e.getMessage()); } @Override public void onResponse(MusicBean response, int id) { dissmiss(); if ("0".equals(response.getCode()) && response.getData() != null && !response.getData().isEmpty()) { restList = response.getData(); // 获取第三条之后的数据(即从索引2开始到末尾) musicList = new ArrayList<>(restList.subList(3, restList.size())); MusicCache.setMainMusicList(musicList); // 缓存主列表 startPlaybackIfNeeded(); } else { ToastUtil.showShortToast("暂无歌曲数据"); } } }); } /** * 设置歌词样式 */ private void initLyricStyle(){ // 应用样式 lyricView.getLrcSetting() .setTimeTextSize(40) .setSelectLineColor(Color.parseColor("#FFFFFFFF")) .setSelectLineTextSize(25) .setNormalRowColor(Color.parseColor("#919191")) .setHeightRowColor(Color.parseColor("#FFFFFFFF")) .setNormalRowTextSize(DensityUtil.sp2px(getContext(), 17)) .setHeightLightRowTextSize(DensityUtil.sp2px(getContext(), 17)) .setTrySelectRowTextSize(DensityUtil.sp2px(getContext(), 17)) .setTimeTextColor(Color.parseColor("#FFFFFFFF")) .setTrySelectRowColor(Color.parseColor("#FFFFFFFF")); lyricView.commitLrcSettings(); } /** * 旋转动画 */ private void initRotationAnimation() { // 创建围绕 Z 轴旋转的动画 rotationAnimator = ObjectAnimator.ofFloat(iv_song, "rotation", 0f, 360f); rotationAnimator.setDuration(10000); // 一圈10秒,可根据需要调整速度 rotationAnimator.setRepeatCount(ObjectAnimator.INFINITE); // 无限循环 rotationAnimator.setInterpolator(new LinearInterpolator()); // 匀速转动 } /** * 如果还没有播放,则自动播放第一首 */ private void startPlaybackIfNeeded() { if (musicList == null || musicList.isEmpty()) return; // 默认从第0首开始播放(如果还没播放过) if (MusicPlayerManager.getInstance().getCurrentPlayingPosition() == -1) { playMusicByPosition(0); } else { updateUIWithCurrentSong(); // 否则刷新当前 UI } setupUpdateProgressWithHandler(); // 开始定时更新进度 } /** * 播放指定位置的歌曲 */ private void playMusicByPosition(int position) { if (musicList == null || position < 0 || position >= musicList.size()) return; MusicBean.DataBean song = musicList.get(position); String url = song.getMusic(); // 假设 getMusic() 返回音频 URL MusicPlayerManager.getInstance().play(url, position); } /** * 上一首 */ private void playPrevious() { if (musicList == null || musicList.isEmpty()) return; int pos = MusicPlayerManager.getInstance().getCurrentPlayingPosition(); int prevPos = (pos - 1 + musicList.size()) % musicList.size(); // 循环上一首 playMusicByPosition(prevPos); } /** * 下一首 */ private void playNext() { if (musicList == null || musicList.isEmpty()) return; int pos = MusicPlayerManager.getInstance().getCurrentPlayingPosition(); int nextPos = (pos + 1) % musicList.size(); // 循环下一首 playMusicByPosition(nextPos); } /** * 播放/暂停切换 */ private void togglePlayPause() { if (MusicPlayerManager.getInstance().isPlaying()) { MusicPlayerManager.getInstance().pause(); } else { MusicPlayerManager.getInstance().resume(); } } /** * 更新 UI 显示当前歌曲信息(包括歌词、标题等) */ @SuppressLint("StaticFieldLeak") private void updateUIWithCurrentSong() { MusicBean.DataBean currentSong = MusicPlayerManager.getInstance().getCurrentPlayingSong(); if (currentSong == null) return; String lrcText = currentSong.getLrc(); tv_title.setText(currentSong.getTitle()); tv_singer.setText(currentSong.getSinger()); // 使用 Glide 加载封面 Glide.with(getContext()) .load(currentSong.getCover()) .transform(new CircleCrop()) .into(iv_song); new AsyncTask<String, Void, List<LrcRow>>() { @Override protected List<LrcRow> doInBackground(String... params) { return new LrcDataBuilder().builtFromText(params[0]); } @Override protected void onPostExecute(List<LrcRow> rows) { if (rows != null && !rows.isEmpty()) { lyricView.setLrcData(rows); tv_no_lyric.setVisibility(View.GONE); } else { lyricView.setLrcData(null); tv_no_lyric.setVisibility(View.VISIBLE); } } }.execute(lrcText); // 更新时间(模拟或通过 MediaPlayer 获取) int duration = MusicPlayerManager.getInstance().getDuration(); tv_end_time.setText(formatTime(duration)); } /** * 定时更新播放进度条和歌词 */ private void setupUpdateProgressWithHandler() { if (handler == null) { handler = new Handler(Looper.getMainLooper()); } // 定义循环任务 updateProgressRunnable = new Runnable() { @Override public void run() { int currentPosition = MusicPlayerManager.getInstance().getCurrentPosition(); int duration = MusicPlayerManager.getInstance().getDuration(); if (duration > 0) { // 更新进度条 int progress = (int) (((float) currentPosition / duration) * 100); seekbar.setProgress(progress); // 更新时间文本 tv_start_time.setText(formatTime(currentPosition)); //通知 LrcView 当前播放时间(毫秒) lyricView.seekLrcToTime(currentPosition); } // 自动重复执行(每隔 500ms) handler.postDelayed(this, 500); } }; // 开始执行 handler.post(updateProgressRunnable); } /** * 格式化毫秒时间为 mm:ss */ private String formatTime(int timeMs) { int totalSeconds = timeMs / 1000; int minutes = totalSeconds / 60; int seconds = totalSeconds % 60; return String.format("%02d:%02d", minutes, seconds); } /** * 绑定播放器状态监听器 */ @Override public void onResume() { super.onResume(); MusicPlayerManager.getInstance().setOnPlaybackStateChangedListener(playbackListener); if (musicList != null) { // 更新当前歌曲信息和播放按钮图标 updateUIWithCurrentSong(); updatePlayButtonState(MusicPlayerManager.getInstance().isPlaying()); boolean isPlaying = MusicPlayerManager.getInstance().isPlaying(); updatePlayButtonState(isPlaying); // 如果正在播放,则恢复旋转 if (isPlaying) { startRotation(); } else { pauseRotation(); } // 恢复进度条更新 setupUpdateProgressWithHandler(); } } @Override public void onPause() { super.onPause(); // 明确判断当前是否正在播放,如果是,则暂停 // 仅当允许暂停时才真正 pause if (shouldPauseWhenBackground && MusicPlayerManager.getInstance().isPlaying()) { MusicPlayerManager.getInstance().pause(); Log.d("HomeFragment", "Fragment 不可见,已暂停音乐"); } pauseRotation(); // 离开界面时停止旋转 // 停止 UI 更新任务 if (handler != null && updateProgressRunnable != null) { handler.removeCallbacks(updateProgressRunnable); } // 移除播放状态监听(避免内存泄漏) MusicPlayerManager.getInstance().setOnPlaybackStateChangedListener(null); } @Override public void onStart() { super.onStart(); // 恢复进度条更新 setupUpdateProgressWithHandler(); boolean isPlaying = MusicPlayerManager.getInstance().isPlaying(); updatePlayButtonState(isPlaying); if (isPlaying) { startRotation(); } else { pauseRotation(); } // 重新绑定监听器 MusicPlayerManager.getInstance().setOnPlaybackStateChangedListener(playbackListener); } @Override public void onDestroy() { super.onDestroy(); MusicPlayerManager.getInstance().release(); // 防止内存泄漏 if (rotationAnimator != null) { rotationAnimator.cancel(); rotationAnimator = null; } if (handler != null) { handler.removeCallbacksAndMessages(null); // 清空所有消息 handler = null; } } // 播放状态监听器 private final MusicPlayerManager.OnPlaybackStateChangedListener playbackListener = new MusicPlayerManager.OnPlaybackStateChangedListener() { private int consecutiveErrorCount = 0; // 连续错误计数 private static final int MAX_CONSECUTIVE_ERRORS = 3; @Override public void onPlaying(int position) { consecutiveErrorCount = 0; // 成功播放则清零 updatePlayButtonState(true); updateUIWithCurrentSong(); } @Override public void onPaused() { updatePlayButtonState(false); } @Override public void onCompletion() { playNext(); // 正常播放完成才切下一首 } @Override public void onError(String errorMsg) { consecutiveErrorCount++; Log.e("MusicPlayer", "播放错误 [" + consecutiveErrorCount + "]: " + errorMsg); // 显示一次错误提示即可 if (consecutiveErrorCount == 1) { ToastUtil.showShortToast("播放失败,跳过该歌曲"); } // 防止无限循环:最多连续失败3次就停止 if (consecutiveErrorCount >= MAX_CONSECUTIVE_ERRORS) { ToastUtil.showShortToast("连续播放失败,已暂停"); MusicPlayerManager.getInstance().pause(); return; } // 尝试播放下一首 playNext(); } }; /** * 更新播放按钮图标(播放/暂停) */ private void updatePlayButtonState(boolean isPlaying) { if (isPlaying) { iv_bf.setImageResource(R.mipmap.img_gc_zt); // 暂停图标 startRotation(); // 开始旋转 } else { iv_bf.setImageResource(R.mipmap.img_bf); // 播放图标 pauseRotation(); // 暂停旋转 } } /** * 开始旋转封面图 */ private void startRotation() { if (isRotating || rotationAnimator == null) return; // 计算从哪里开始(支持恢复) float currentRotation = iv_song.getRotation(); rotationAnimator.setFloatValues(currentRotation, currentRotation + 360f); rotationAnimator.start(); isRotating = true; } /** * 暂停旋转封面图 */ private void pauseRotation() { if (!isRotating || rotationAnimator == null) return; rotationAnimator.cancel(); // cancel 会保留当前角度 isRotating = false; } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); } @Override public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) { if(requestCode == RC_CAMERA_PERM){ saveCurrentSong(); } // 恢复正常行为:离开界面时暂停 shouldPauseWhenBackground = true; } @Override public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) { // 即使拒绝,也恢复标志 shouldPauseWhenBackground = true; } // 内部歌词解析器 public static class LrcDataBuilder { // 加上 static public List<LrcRow> builtFromText(String lrcText) { List<LrcRow> rows = new ArrayList<>(); if (lrcText == null || lrcText.trim().isEmpty()) { return rows; } String[] lines = lrcText.split("\\r?\\n"); for (String line : lines) { line = line.trim(); if (line.isEmpty()) continue; List<LrcRow> parsed = parseLrcLine(line); if (!parsed.isEmpty()) { rows.addAll(parsed); } } Collections.sort(rows); return rows; } private List<LrcRow> parseLrcLine(String line) { List<LrcRow> result = new ArrayList<>(); if (line.isEmpty()) return result; // 支持多种换行符预处理(避免后续污染) line = line.replaceAll("[\\r\\n\\u2028\\u2029]+", " "); Pattern pattern = Pattern.compile("\\[(\\d{1,2}):(\\d{2})(?:\\.(\\d{2,3}))?\\]"); Matcher matcher = pattern.matcher(line); while (matcher.find()) { int min = Integer.parseInt(matcher.group(1)); int sec = Integer.parseInt(matcher.group(2)); int milli = 0; if (matcher.group(3) != null) { milli = Integer.parseInt(matcher.group(3)); if (matcher.group(3).length() == 2) milli *= 10; // 补齐毫秒 } long timeMillis = (min * 60L + sec) * 1000 + milli; int textStart = matcher.end(); int textEnd = line.length(); // 查找下一个时间标签作为结束点 Matcher nextMatcher = pattern.matcher(line); if (nextMatcher.find(matcher.start() + 1)) { textEnd = nextMatcher.start(); } String rawText = line.substring(textStart, textEnd).trim(); // 再次防御性清理各种空白与特殊字符 String text = rawText .replaceAll("[\\p{Cc}\\p{Cf}&&[^\\t]]", " ") // 移除控制字符 .replace((char) 0xA0, ' ') // 不间断空格 .replaceAll("\\s+", " ") // 多空格合并 .trim(); if (!text.isEmpty()) { result.add(new LrcRow(text, matcher.group(0), timeMillis)); } } return result; } } private void getSavePermissions() { // 检查并请求权限 if (!EasyPermissions.hasPermissions(getContext(), PERMS_CAMERA)) { new PermissionDialog(getActivity(),"权限说明:由于下载歌曲,需要相应的存储权限。拒绝将无法使用此功能").show(); EasyPermissions.requestPermissions(getActivity(), "需要相应的存储权限", RC_CAMERA_PERM, PERMS_CAMERA); } else { saveCurrentSong(); // 改为保存当前歌曲 } } private void saveCurrentSong() { int pos = MusicPlayerManager.getInstance().getCurrentPlayingPosition(); if (pos == -1) { ToastUtil.showShortToast("没有正在播放的歌曲"); return; } MusicBean.DataBean song = musicList.get(pos); if (song == null || song.getMusic() == null) { ToastUtil.showShortToast("歌曲信息不完整"); return; } showProgressDialog(getActivity()); new SaveTask(song).execute(); // 传入整个 song 对象更安全 } private void showProgressDialog(Context context) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setMessage("正在保存..."); builder.setCancelable(false); progressDialog = builder.create(); progressDialog.show(); } private class SaveTask extends AsyncTask<Void, Void, Boolean> { private final MusicBean.DataBean song; private String targetPath; private Exception exception; SaveTask(MusicBean.DataBean song) { this.song = song; } @Override protected Boolean doInBackground(Void... voids) { try { String urlStr = song.getMusic(); String fileName = song.getTitle(); if (fileName == null) fileName = "music_" + System.currentTimeMillis(); File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); if (!dir.exists()) dir.mkdirs(); targetPath = new File(dir, fileName + ".mp3").getAbsolutePath(); InputStream inputStream = new java.net.URL(urlStr).openStream(); FileOutputStream outStream = new FileOutputStream(targetPath); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outStream.write(buffer, 0, bytesRead); } outStream.flush(); outStream.close(); inputStream.close(); // 通知媒体库刷新 Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); scanIntent.setData(Uri.fromFile(new File(targetPath))); getActivity().sendBroadcast(scanIntent); return true; } catch (Exception e) { e.printStackTrace(); exception = e; return false; } } @Override protected void onPostExecute(Boolean success) { if (progressDialog != null && progressDialog.isShowing()) { progressDialog.dismiss(); } if (success) { Toast.makeText(getActivity(), "音乐已保存至: " + targetPath, Toast.LENGTH_LONG).show(); } else { Toast.makeText(getActivity(), "保存失败: " + (exception != null ? exception.getMessage() : "未知错误"), Toast.LENGTH_SHORT).show(); } } } }package com.weishitechsub.quanminchangKmianfei.fragment.lilv; import androidx.recyclerview.widget.RecyclerView; import com.hfd.common.base.BaseFragment; import com.weishitechsub.quanminchangKmianfei.R; /** * 个人出租屋税率 */ public class LiLvFragment extends BaseFragment{ RecyclerView rv; @Override protected int setLayout() { return R.layout.fragment_lilv; } @Override protected void initView() { } @Override protected void initClick() { } @Override protected void initData() { } } package com.weishitechsub.quanminchangKmianfei.utils; import com.weishitechsub.quanminchangKmianfei.bean.MusicBean; import java.util.ArrayList; import java.util.List; public class MusicCache { // 主音乐列表(如首页推荐、搜索结果) private static List<MusicBean.DataBean> mainMusicList; // 当前正在播放的歌曲 private static MusicBean.DataBean currentPlayingSong; // 当前播放位置(可选,用于定位) private static int currentPosition = -1; // === 主列表操作 === public static void setMainMusicList(List<MusicBean.DataBean> list) { if (list != null) { mainMusicList = new ArrayList<>(list); } else { mainMusicList = null; } } public static List<MusicBean.DataBean> getMainMusicList() { return mainMusicList; } public static MusicBean.DataBean getMusicAt(int position) { if (mainMusicList == null || position < 0 || position >= mainMusicList.size()) { return null; } return mainMusicList.get(position); } // === 当前播放歌曲操作 === public static void setCurrentPlayingSong(MusicBean.DataBean song, int position) { currentPlayingSong = song; currentPosition = position; } public static MusicBean.DataBean getCurrentPlayingSong() { return currentPlayingSong; } public static int getCurrentPlayingPosition() { return currentPosition; } // 可选:清空当前播放 public static void clearCurrentPlaying() { currentPlayingSong = null; currentPosition = -1; } } 我在LiLvFragment展示 MusicCache.setMainMusicList(musicList); // 缓存主列表直接用这个展示数据可以吗
最新发布
12-10
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值