可以滑动切歌的播放控制条(模仿QQ音乐)

Apr 7 2015

看了QQ音乐Android版有这个功能,觉得挺好玩的,就模仿它做了一个demo,可以滑动切歌(转换的gif严重失真,只能截图了 -.-)

项目地址:https://github.com/bxbxbai/SwipePlaybarDemo

下载地址:http://vdisk.weibo.com/s/GGofvp4_QVU/1428410542

底部播放条的歌曲信息可以滑动切换,并且专辑图会转动

看看截图

这个是4个播放条的截图:
playbar

实现

这个功能就是使用ViewPager这个组件来实现,然后最主要的就是为这个ViewPager写一个PagerAapter。这个PagerAdapter写起来也容易,但是我在这个类里做了一些优化。

这个PagerAdapter的全部代码就在下面:

/**
  * PlayBar ViewPager Adapter 
  * 
  * @author bxbxbai
*/
public class PlayCtrlBarPagerAdapter extends PagerAdapter {

  private static final int NUM_SONGS = 10;
  private static final int ANIMATOR_DURATION = 1000 * 10;

  private LayoutInflater mInflater;

  private Queue<View> mReusableViews;


  public PlayCtrlBarPagerAdapter(Context context) {
    mInflater = LayoutInflater.from(context);
    mReusableViews = new ArrayDeque<>(NUM_SONGS);
  }

  @Override
  public int getCount() {
    return NUM_SONGS;
  }

  @Override
  public boolean isViewFromObject(View view, Object object) {
    return view == object;
  }

  @Override
  public void destroyItem(ViewGroup container, int position, Object object) {
    if (object instanceof View) {
        container.removeView((View) object);
        mReusableViews.add((View) object);
    }
  }

  @Override
  public Object instantiateItem(ViewGroup container, int position) {
    View v = mReusableViews.poll();
    if (v == null) {
        v = mInflater.inflate(R.layout.layout_music, container, false);
        setAnimator(v);
    }
    bindData(v, position);
    container.addView(v);
    return v;
 }

  private void bindData(View v, int position) {
    TextView songName = ButterKnife.findById(v, R.id.tv_song_name);
    songName.setText("Try - " + position);

    ImageView artistImage = ButterKnife.findById(v, R.id.iv_artist_cover);
    if (position % 2 == 1) {
        artistImage.setImageResource(R.drawable.adele);
    } else {
        artistImage.setImageResource(R.drawable.bxbxbai);
    }
 }

  @Override
  public float getPageWidth(int position) {
    return 1.0f;
  }

  public static void setAnimator(View view) {
    ObjectAnimator animator = ObjectAnimator.ofFloat(view.findViewById(R.id.iv_artist_cover), "rotation", 0f, 360f);
    animator.setRepeatCount(Integer.MAX_VALUE);
    animator.setDuration(ANIMATOR_DURATION);
    animator.setInterpolator(new LinearInterpolator());

    view.setTag(R.id.tag_animator, animator);
  }
}

优化PagerAdapter

PagerAdapter和Android中ListViewAdapter类似,但是一个主要的不同就是PagerAdapter提供了一个回调方法来让我们处理销毁的Item。

一个ViewPager默认的offScreenPageLimit为1,也就是说当一个ViewPager当前显示页为2,那么PagerAdapter中还存在左右两个Pager,也就是13。此时,如果我们将ViewPager滑向3,那么PagerAdapter首先会通过public void destroyItem(ViewGroup container, int position, Object object)方法销毁第1个Item,然后通过public Object instantiateItem(ViewGroup container, int position)生成第4的Item,并且显示当前的Item(为3)。此时,PagerAdapter中存在的Item为24

从这个思路出发,我也就可以在destroyItem方法中保存这个object,然后在instantiateItem中使用。

看上面的代码

我写了一个Queue<View> mReusableViews;destroyItem中保存被销毁的Item,然后在instantiateItem方法中首先去mReusableViews中获取。

如果存在可以重用的Item,那么就不用inflate一个View了,直接绑定数据就可以。否则就创建一个新的View来使用

在实验过程中发现,如果ViewPageroffScreenPageLimit为1,那么只需要创建3个View,其他的View都可以重复使用,这样就可以提升性能了

##如何让ImageView转起来

View绑定数据的时候通过一个工具方法,为每个View都设置一个ObjectAnimator属性动画。然后我为这个ViewPager专门写了一个ViewPager.PageTransformer

其实代码也很简单,就是当某一个page完全显示的时候(position为0),开始动画,否则停止动画

如果你需要在ViewPager上添加一些其他特效,那么可以通过addTransformer方法添加PageTransformer

/**
 * 播放条的PagerTransformer
 *
 * @author bxbxbai
 */
public class PlaybarPagerTransformer implements ViewPager.PageTransformer {

  private List<ViewPager.PageTransformer> mTransformers = new ArrayList<>();

  @Override
  public void transformPage(View page, float position) {
    for (ViewPager.PageTransformer transformer : mTransformers) {
        transformer.transformPage(page, position);
    }

    //处理图片旋转

    StopWatch.log("page: " + page + ", pos: " + position);

    if (position == 0) {
        ObjectAnimator animator = (ObjectAnimator) page.getTag(R.id.tag_animator);
        if (animator != null) {
            animator.start();
        }
    } else if (position == -1 || position == -2 || position == 1) {
        ObjectAnimator animator = (ObjectAnimator) page.getTag(R.id.tag_animator);
        if (animator != null) {
            animator.end();
        }
    }
  }


  public void addTransformer(ViewPager.PageTransformer transformer) {
    if (transformer != null) {
        mTransformers.add(transformer);
    }
  }
}

Dependency - 依赖

  • Java Development Kit (JDK) 7 +
  • com.android.tools.build:gradle:1.0.0
  • Android SDK
    • Android SDK Build-tools 21.1.2

Build - 构建

git clone https://github.com/bxbxbai/SwipePlaybarDemo.git

用最新的IntelliJ IDE导入工程(Import Project),然后等待IDE下载gradle和依赖包即可