a beautiful MusicPlayer for Android
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.idea Initial commit Jan 9, 2019
Screenshot Initial commit Jan 9, 2019
app Initial commit Jan 9, 2019
gradle/wrapper Initial commit Jan 9, 2019
library Initial commit Jan 9, 2019
.gitignore Initial commit Jan 9, 2019
README.md Update README.md Jan 9, 2019
app-debug.apk demo_apk Jan 9, 2019
build.gradle Initial commit Jan 9, 2019
gradle.properties Initial commit Jan 9, 2019
gradlew Initial commit Jan 9, 2019
gradlew.bat Initial commit Jan 9, 2019
settings.gradle Initial commit Jan 9, 2019

README.md

MusicPlayerdemo

a MusicPlayer for Android

仿网易云音乐 可扫描本地音乐播放

核心播放页 唱盘的实现

1:首先是背景高斯迷糊,先切割图片一部分,然后缩小图片,利用FastBlur高斯模糊 最后加上灰色遮罩

 private Drawable getForegroundDrawable(int musicPicRes) {
        /*得到屏幕的宽高比,以便按比例切割图片一部分*/
        final float widthHeightSize = (float) (DisplayUtil.getScreenWidth(MusicPlayActivity.this)
                * 1.0 / DisplayUtil.getScreenHeight(this) * 1.0);

        Bitmap bitmap = getForegroundBitmap(musicPicRes);
        int cropBitmapWidth = (int) (widthHeightSize * bitmap.getHeight());
        int cropBitmapWidthX = (int) ((bitmap.getWidth() - cropBitmapWidth) / 2.0);

        /*切割部分图片*/
        Bitmap cropBitmap = Bitmap.createBitmap(bitmap, cropBitmapWidthX, 0, cropBitmapWidth,
                bitmap.getHeight());
        /*缩小图片*/
        Bitmap scaleBitmap = Bitmap.createScaledBitmap(cropBitmap, bitmap.getWidth() / 50, bitmap
                .getHeight() / 50, false);
        /*模糊化*/
        final Bitmap blurBitmap = FastBlurUtil.doBlur(scaleBitmap, 8, true);

        final Drawable foregroundDrawable = new BitmapDrawable(blurBitmap);
        /*加入灰色遮罩层,避免图片过亮影响其他控件*/
        foregroundDrawable.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
        return foregroundDrawable;
    }

    private Bitmap getForegroundBitmap(int musicPicRes) {
        int screenWidth = DisplayUtil.getScreenWidth(this);
        int screenHeight = DisplayUtil.getScreenHeight(this);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        BitmapFactory.decodeResource(getResources(), musicPicRes, options);
        int imageWidth = options.outWidth;
        int imageHeight = options.outHeight;

        if (imageWidth < screenWidth && imageHeight < screenHeight) {
            return BitmapFactory.decodeResource(getResources(), musicPicRes);
        }

        int sample = 2;
        int sampleX = imageWidth / DisplayUtil.getScreenWidth(this);
        int sampleY = imageHeight / DisplayUtil.getScreenHeight(this);

        if (sampleX > sampleY && sampleY > 1) {
            sample = sampleX;
        } else if (sampleY > sampleX && sampleX > 1) {
            sample = sampleY;
        }

        options.inJustDecodeBounds = false;
        options.inSampleSize = sample;
        options.inPreferredConfig = Bitmap.Config.RGB_565;

        return BitmapFactory.decodeResource(getResources(), musicPicRes, options);
    }

2:合成唱盘 首先设置一个透明的圆背景 RoundedBitmapDrawable 然后拿到封面,生成圆形Drawable,还有黑胶部分,之后利用LayerDrawable(它类似ps的图层,可以将一个数组里的drawable合成一个drawable 索引最大盖在最上面) 把封面和黑胶合成唱片,这里还对图片进行了压缩避免oom

/*得到唱盘背后半透明的圆形背景*/
   private Drawable getDiscBlackgroundDrawable() {
       int discSize = (int) (mScreenWidth * DisplayUtil.SCALE_DISC_SIZE);
       Bitmap bitmapDisc = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(),
               R.drawable.ic_disc_blackground), discSize, discSize, false);
       RoundedBitmapDrawable roundDiscDrawable = RoundedBitmapDrawableFactory.create
               (getResources(), bitmapDisc);
       return roundDiscDrawable;
   }

   /**
    * 得到唱盘图片
    * 唱盘图片由空心圆盘及音乐专辑图片“合成”得到
    */
   private Drawable getDiscDrawable(int musicPicRes) {
       int discSize = (int) (mScreenWidth * DisplayUtil.SCALE_DISC_SIZE);
       int musicPicSize = (int) (mScreenWidth * DisplayUtil.SCALE_MUSIC_PIC_SIZE);

       Bitmap bitmapDisc = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(),
               R.drawable.ic_disc), discSize, discSize, false);
       Bitmap bitmapMusicPic = getMusicPicBitmap(musicPicSize, musicPicRes);
       BitmapDrawable discDrawable = new BitmapDrawable(bitmapDisc);
       RoundedBitmapDrawable roundMusicDrawable = RoundedBitmapDrawableFactory.create
               (getResources(), bitmapMusicPic);

       //抗锯齿
       discDrawable.setAntiAlias(true);
       roundMusicDrawable.setAntiAlias(true);

       Drawable[] drawables = new Drawable[2];
       drawables[0] = roundMusicDrawable;
       drawables[1] = discDrawable;

       LayerDrawable layerDrawable = new LayerDrawable(drawables);
       int musicPicMargin = (int) ((DisplayUtil.SCALE_DISC_SIZE - DisplayUtil
               .SCALE_MUSIC_PIC_SIZE) * mScreenWidth / 2);
       //调整专辑图片的四周边距,让其显示在正中
       layerDrawable.setLayerInset(0, musicPicMargin, musicPicMargin, musicPicMargin,
               musicPicMargin);

       return layerDrawable;
   }

   private Bitmap getMusicPicBitmap(int musicPicSize, int musicPicRes) {
       BitmapFactory.Options options = new BitmapFactory.Options();
       options.inJustDecodeBounds = true;

       BitmapFactory.decodeResource(getResources(), musicPicRes, options);
       int imageWidth = options.outWidth;

       int sample = imageWidth / musicPicSize;
       int dstSample = 1;
       if (sample > dstSample) {
           dstSample = sample;
       }
       options.inJustDecodeBounds = false;
       //设置图片采样率
       options.inSampleSize = dstSample;
       //设置图片解码格式
       options.inPreferredConfig = Bitmap.Config.RGB_565;

       return Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(),
               musicPicRes, options), musicPicSize, musicPicSize, true);
   }

3:唱盘指针 其实是一张图片,设置它的旋转起始坐标点,监听viewPager的滑动利用ObjectAnimator旋转指针

 private void initNeedle() {
       mIvNeedle = (ImageView) findViewById(R.id.ivNeedle);

       int needleWidth = (int) (DisplayUtil.SCALE_NEEDLE_WIDTH * mScreenWidth);
       int needleHeight = (int) (DisplayUtil.SCALE_NEEDLE_HEIGHT * mScreenHeight);

       /*设置手柄的外边距为负数,让其隐藏一部分*/
       int marginTop = (int) (DisplayUtil.SCALE_NEEDLE_MARGIN_TOP * mScreenHeight) * -1;
       int marginLeft = (int) (DisplayUtil.SCALE_NEEDLE_MARGIN_LEFT * mScreenWidth);

       Bitmap originBitmap = BitmapFactory.decodeResource(getResources(), R.drawable
               .ic_needle);
       Bitmap bitmap = Bitmap.createScaledBitmap(originBitmap, needleWidth, needleHeight, false);

       LayoutParams layoutParams = (LayoutParams) mIvNeedle.getLayoutParams();
       layoutParams.setMargins(marginLeft, marginTop, 0, 0);

       int pivotX = (int) (DisplayUtil.SCALE_NEEDLE_PIVOT_X * mScreenWidth);
       int pivotY = (int) (DisplayUtil.SCALE_NEEDLE_PIVOT_Y * mScreenWidth);

       mIvNeedle.setPivotX(pivotX);
       mIvNeedle.setPivotY(pivotY);
       mIvNeedle.setRotation(DisplayUtil.ROTATION_INIT_NEEDLE);
       mIvNeedle.setImageBitmap(bitmap);
       mIvNeedle.setLayoutParams(layoutParams);
   }

   private void initObjectAnimator() {
       mNeedleAnimator = ObjectAnimator.ofFloat(mIvNeedle, View.ROTATION, DisplayUtil
               .ROTATION_INIT_NEEDLE, 0);
       mNeedleAnimator.setDuration(DURATION_NEEDLE_ANIAMTOR);
       mNeedleAnimator.setInterpolator(new AccelerateInterpolator());
       mNeedleAnimator.addListener(new Animator.AnimatorListener() {
           @Override
           public void onAnimationStart(Animator animator) {
               /**
                * 根据动画开始前NeedleAnimatorStatus的状态,
                * 即可得出动画进行时NeedleAnimatorStatus的状态
                * */
               if (needleAnimatorStatus == NeedleAnimatorStatus.IN_FAR_END) {
                   needleAnimatorStatus = NeedleAnimatorStatus.TO_NEAR_END;
               } else if (needleAnimatorStatus == NeedleAnimatorStatus.IN_NEAR_END) {
                   needleAnimatorStatus = NeedleAnimatorStatus.TO_FAR_END;
               }
           }

           @Override
           public void onAnimationEnd(Animator animator) {

               if (needleAnimatorStatus == NeedleAnimatorStatus.TO_NEAR_END) {
                   needleAnimatorStatus = NeedleAnimatorStatus.IN_NEAR_END;
                   int index = mVpContain.getCurrentItem();
                   playDiscAnimator(index);
                   musicStatus = MusicStatus.PLAY;
               } else if (needleAnimatorStatus == NeedleAnimatorStatus.TO_FAR_END) {
                   needleAnimatorStatus = NeedleAnimatorStatus.IN_FAR_END;
                   if (musicStatus == MusicStatus.STOP) {
                       mIsNeed2StartPlayAnimator = true;
                   }
               }

               if (mIsNeed2StartPlayAnimator) {
                   mIsNeed2StartPlayAnimator = false;
                   /**
                    * 只有在ViewPager不处于偏移状态时,才开始唱盘旋转动画
                    * */
                   if (!mViewPagerIsOffset) {
                       /*延时500ms*/
                       DiscView.this.postDelayed(new Runnable() {
                           @Override
                           public void run() {
                               playAnimator();
                           }
                       }, 50);
                   }
               }
           }

           @Override
           public void onAnimationCancel(Animator animator) {

           }

           @Override
           public void onAnimationRepeat(Animator animator) {

           }
       });
   }

利用媒体库查询语句扫描本地音乐并返回集合

// 媒体库查询语句(写一个工具类MusicUtils)
        try {
            Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    null, null, null, MediaStore.Audio.AudioColumns.IS_MUSIC);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    Song song = new Song();
                    song.song = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
                    song.singer = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
                    song.path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
                    song.duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
                    song.size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
                    song.image = pan[new Random().nextInt(pan.length)];
//                    song.image = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
                    if (song.size > 1000 * 800) {
                        // 注释部分是切割标题,分离出歌曲名和歌手 (本地媒体库读取的歌曲信息不规范)
                        if (song.song.contains("-")) {
                            String[] str = song.song.split("-");
                            song.singer = str[0];
                            song.song = str[1];
                        }
                        list.add(song);
                    }
                }
                // 释放资源
                cursor.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }