最近在开发一款高仿QQ音乐播放器的Demo,遇到了一个问题,在QQ音乐主界面有一个常驻底部栏,底部栏中有一个可左右滑动切歌的组件,最后还是实现了效果,今天来回顾一下实现过程。

要实现的就是最下方的常驻底部栏。

常驻底部栏

首先,当我第一次拿到这个问题的时候我先对这个问题进行了分析,我做的第一步是分析这个组件有什么特点,一下是我总结的特点:

1.无限轮播,可循环

2.第一次进入就可以左右滑动

3.每个view的界面时相同的。

4.可以监听侧滑,需要实现侧滑事件。

综上所诉,我确定了两个可能可以实现的组件:

1.ViewPager2.横向的RecycleView

但各有利弊,ViewPager首先不能实现无限轮播,个数是有限的,不能循环,其次Viewpager第一次进入时不可以左滑(当初始index=0,是不能左滑的)。横向RecycleView没有滑动效果,无法监听侧滑,当然两个条件也无法轻易实现(当时想到RecycleView主要是因为看起来效果像个ListView,但是是横向的,所以就想到近期使用的RecycleView...)

想了很久,最后决定是用ViewPager实现,既然决定实现方式,就要考虑怎么实现,所以实现的关键点就是:无线轮播,循环。

在网上搜索了一下之类的关键词,实现方式无非两种:

1.有三张图片,实现无限循环。在viewpager中设置5个view,第一个为三张图片的最后一张,第五张为三张图片的第一张。

这里写图片描述

2.将数量设置足够大,然后将初始位置放在中间

这里分析一下两种实现方式,第一种,实质是对数据的处理,让一开始处于index=1,在列表头加一项,在列表尾加一项,然后实现滑动监听,滑到第一个的时候,通过setCurrentItem实现跳转。

这个看起来可以实现我们的需求,但是还是有一些问题:

1.需要对数据进行处理,当数据量小的时候,逻辑好处理,但对于这次的需求,音乐播放器,歌曲数量非常大的时候,比较麻烦。

2.这个实现还是脱离不了View,也就是说1000首歌需要分配内存1000个View,这样分配内存在回收内存,非常不合理。(这是我不采用的主要原因)

第二种实现方式,其实挺无奈的。。。虽然这种实现方式确实可以实现,但是还是脱离不了那个实质性问题占用内存!

问题进展到这有点无法前进了,我在网上搜了许多方式,但是网上大多是千篇一律的(这是现在很多博客的通病),没办法我就自己思考这个问题的实现方式,这个问题现在的难点是怎么让它高性能,不用愚蠢的有多少首歌就需要new多少View或者说Fragment,这样是很占用内存的。

这让我回到最开始分析问题的时候,这个组件有一个特点,那就是,每一页的View布局都是相同的,那岂不是和ListView一样,所以我就想到了ListView的缓存机制。

这里写图片描述

没错就是复用View

这个就是我想到的实现思路,Viewpager也可以像ListView一样复用View,这样就不用一个一个声明View了。

找到问题的解决方式,现在就说一下具体实现步骤吧:

这里写图片描述

1.数据处理保证第一次左右都可以划,如果初始在index=0,第一次进入是不可以左滑的,因为左边没有东西。。。

2.滑动监听,当滑动到index=1时,跳转到最后一项。

if ( position < 1) { //首位之前,跳转到末尾

cycleViewPager.setCurrentItem(position,false);

(这里面false很重要,因为如果你不加false,就会显示滑动效果,这时从第一项滑到最后一项,要显示多少效果。。。,而且监听只用监听从1变到最后一项,从最后一项变到第一项不用监听,因为我实现过,发现从最后一项调回到第一项,会发生ANR,但是从第一项变到最后一项就不会,我也不知道为啥。。。当到达最后一项的时候,去余即可)

3.自定义adapter(仿ListView的缓存机制,复用view)

4.取余

position = position%datas.size() == 0?1:position%datas.size()+1;

View的复用机制很简单,就是建立一个缓存Cache,重写PagerAdapter

关键代码如下:

public void destroyItem() {

View contentView = (View) object;

container.removeView(contentView);

//destroy的时候把View加入缓存

viewCache.add(contentView);

}

public view getView(){

//getView的时候从缓存拿或者new

if(viewCache.size() == 0){

convertView = layoutInflater.inflate(R.layout.bottom_layout_item,null,false);

viewHolder = new ViewHolder(convertView);

convertView.setTag(viewHolder);

}else{

//getView的时候从缓存拿

convertView = viewCache.removeFirst();

viewHolder = (ViewHolder) convertView.getTag();

}

粘一下关键代码吧:

BottomViewAdapter .java

package com.project.musicplayer.adapter;

import android.content.Context;

import android.support.v4.view.PagerAdapter;

import android.support.v4.view.ViewPager;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.TextView;

import com.project.musicplayer.R;

import com.project.musicplayer.model.Music;

import com.project.musicplayer.model.Song;

import java.util.HashMap;

import java.util.LinkedList;

import java.util.List;

/**

* Created by Administrator on 2016/7/5.

*/

public class BottomViewAdapter extends PagerAdapter {

public interface OnViewClickListener{

void onViewClicked(int position);

}

private LinkedList viewCache = null;

private List datas;

private LayoutInflater layoutInflater;

private Context mContext;

private OnViewClickListener onViewClickListener;

public void setOnViewClickListener(OnViewClickListener onViewClickListener) {

this.onViewClickListener = onViewClickListener;

}

public BottomViewAdapter(List songList, Context mContext) {

this.datas = songList;

this.mContext = mContext;

this.layoutInflater = LayoutInflater.from(mContext);

this.viewCache = new LinkedList();

}

public void setDatas(List datas){

this.datas = datas;

}

@Override

public int getCount() {

return Integer.MAX_VALUE;

}

@Override

public boolean isViewFromObject(View arg0, Object arg1) {

return arg0 == arg1;

}

@Override

public void destroyItem(ViewGroup container, int position, Object object) {

View contentView = (View) object;

container.removeView(contentView);

viewCache.add(contentView);

}

@Override

public CharSequence getPageTitle(int position) {

return super.getPageTitle(position);

}

@Override

public Object instantiateItem(ViewGroup container, int position) {

View convertView = null;

ViewHolder viewHolder = null;

if(position >= datas.size()){

position = position%datas.size() == 0?1:position%datas.size()+1;

}

/* if(position == 0){

position++;

}*/

if(viewCache.size() == 0){

convertView = layoutInflater.inflate(R.layout.bottom_layout_item,null,false);

viewHolder = new ViewHolder(convertView);

convertView.setTag(viewHolder);

}else{

convertView = viewCache.removeFirst();

viewHolder = (ViewHolder) convertView.getTag();

}

viewHolder.name.setText(datas.get(position).getTitle());

viewHolder.author.setText(datas.get(position).getSinger());

container.addView(convertView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

final int finalPosition = position;

convertView.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

if(onViewClickListener != null){

onViewClickListener.onViewClicked(finalPosition);

}

}

});

return convertView;

}

/**

* 进行View预加载处理

@Override

public void setPrimaryItem(ViewGroup container, int position, Object object) {

// TODO Auto-generated method stub

super.setPrimaryItem(container, position, object);

mIndex = position % listViews.size();

if (loadTag.get(listViews.get(mIndex)) == false) {

mContext.createView(mIndex);

loadTag.put(listViews.get(mIndex), true);

}

}*/

class ViewHolder{

TextView name;

TextView author;

public ViewHolder(View view){

name = (TextView) view.findViewById(R.id.tv_id_name);

author = (TextView) view.findViewById(R.id.tv_id_author);

}

}

}

MainActivity.java

public void onPageSelected(int position) {

mCurrentIndex = position;

if ( songList.size() > 1) { //多于1,才会循环跳转

if ( position < 1) { //首位之前,跳转到末尾(N)

position = songList.size()-1;

cycleViewPager.setCurrentItem(position,false);

}

}

if(position >= songList.size()){

mCurrentIndex = position%songList.size() == 0?1:position%songList.size()+1;

}

mCurrentSong = songList.get(mCurrentIndex);

}

android qq音乐布局,仿QQ音乐底部栏相关推荐

  1. Android开发之高仿QQ消息侧拉删除

    Android开发之高仿QQ消息侧拉删除 QQ消息的侧滑删除效果之炫酷,想必大家都见过吧,本人作为一名安卓开发人员,遇到如此炫酷的效果,怎能不研究一番呢,现本人已实现其基本功能,现将代码贴出,望各位大 ...

  2. android自定义设置界面,Android开发之精仿QQ设置界面(自定义PreferenceActivity)

    Android开发之精仿QQ设置界面(自定义PreferenceActivity) 时间:2011-12-05 10:25:06 来源:Android开发者门户 作者: 今天,再给大家分享一下QQ设置 ...

  3. Android仿QQ ios dialog,仿QQ退出向上菜单

    Android仿QQ ios dialog,仿QQ退出向上菜单 EasyDialog两种模式 仿QQ退出向上菜单,自定义向上菜单              github地址:https://githu ...

  4. Android UI布局—— 仿QQ登录界面

    最近,有点空闲的时间就拿QQ登录界面来模仿练手,做了个简单的登录界面.界面一般般吧,不算很漂亮,现在拿出来分享,希望大家一起学习与进步.有什么不足之处,请各位大侠多多赐教,谢谢.这个界面涉及到Line ...

  5. Android自定义View之仿QQ运动步数进度效果

    文章目录 前言 先看效果图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6e4ddec17933496ea4830fa08d8ffbe5.png?x-oss-pr ...

  6. android 自定义view实现仿QQ运动步数进度效果

    最近公司在策划一个新的项目,原型还没出来,再说这公司人都要走没了,估计又要找工作了,所以必须要学习,争取每个写个关于自定义view方面的,这样几个月积累下来,也能学习到东西,今天就带来简单的效果,就是 ...

  7. android气泡聊天消息背景,Android使用贝塞尔曲线仿QQ聊天消息气泡拖拽效果

    本文实例为大家分享了Android仿QQ聊天消息气泡拖拽效果展示的具体代码,供大家参考,具体内容如下 先画圆,都会吧.代码如下: public class Bezier extends View { ...

  8. android qq右上加号,仿QQ空间点击加号弹出菜单特效

    最近项目需要,前几天写了一个仿微信相册(包括编辑相册)功能,审核代码的时候发现同事要实现一个类似仿QQ空间点击加号弹出菜单特效,于是看了一些他的代码,我发现虽然他实现了功能,但是不够完善,所以我又花了 ...

  9. android幻灯片效果自定义,Android自定义View实现仿网易音乐唱片播放效果

    本文实例为大家分享了Android实现仿网易音乐唱片播放效果的具体代码,供大家参考,具体内容如下 效果图: 在values中创建attrs.xml文件 //中间图片的半径 //图片 //唱片旋转的速度 ...

最新文章

  1. ICCV 华人团队提出会创作的Paint Transformer,网友反驳:这也要用神经网络?
  2. PHPTree——快速生成无限多级分类
  3. 2.2. Array
  4. hibernate 高级映射 --张国亮总结第一季
  5. 10分钟学会vue滚动行为
  6. PID控制器开发笔记之八:带死区的PID控制器的实现
  7. 怎么通过java去调用并执行shell脚本以及问题总结
  8. 外挂摄像头?iPhone XI新概念图曝光:差点就信了...
  9. 用Bi-GRU+Attention和字向量做端到端的中文关系抽取
  10. 内存管理之智能指针shared_ptr
  11. 基于相关向量机RVM的分类算法
  12. maven项目中操作mysql数据库案例
  13. Wowza服务器系列(5):使用rtsp协议向wowza推流的wowoza配置方法
  14. 【京东笔试题】熊猫吃竹子,回溯
  15. 2021全国大学生电子设计竞赛F题(智能送药小车)国一赛后总结
  16. Java练习题【新】
  17. idea中启动项目 就报异常
  18. 公司要抽奖活动?50行Python代码制作了一个转盘抽奖小程序
  19. 【VESC】一.配置开发环境、烧录固件
  20. excel中单元格的回车替换成其他字符

热门文章

  1. 关于2022年12代C/C++Linux服务器开发高级架构师课程体系分析
  2. wordpress添加面包屑
  3. 工程能力(1)设计方法研发流程
  4. linux为steam启用nvidia显卡
  5. 17-阿里云服务器ECS使用教程之Web环境的搭建
  6. 2020G1工业锅炉司炉模拟考试及G1工业锅炉司炉模拟考试软件
  7. Eloquent JavaScript 笔记 十九:Node.js
  8. .NET Framework下载
  9. 微信小游戏全局开启好友和朋友圈分享功能
  10. python 定时播放音乐_python实现闹钟定时播放音乐功能