android开发技巧——直播礼物面板制作

导语:

大家好,很高兴又和大家见面了!我怀着无比激动地心情写下这篇博客,希望能把我在工作中遇到的心得体会分享给大家,让大家少走弯路。希望能和大家一起成长,一起进步。另外希望大家能多多提出自己的想法,一起进步。


一、实现逻辑:

按照项目需求,需要提供给用户20个礼物动画,分3页进行展示。首先我先说一下我的实现思路。

1.实现思路:

ViewPager实现分页滑动的效果;使用GridView实现礼物的列表;通过添加包含礼物Item的GridView到ViewPager实现整体的效果。

按照惯例首先展示给大家效果图:

__

二、代码逻辑:

1.实现ViewPager滑动效果的基本逻辑:

1>首先在activity_main.xml布局文件内添加RelativeLayout布局,在该布局内添加ViewPager控件,并在该控件下方添加一个LinearLayout布局用户显示轮播图的指示器;

代码如下:


   
   

   
   

    
    
    

        
     
     

        
     
     
    
    
    

   
   


2>初始化ViewPager,重写适配器:

代码如下:

package com.zxm.giftlistdemo;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

/**
 * Created by ZXM on 2016/9/12.
 */
public class ViewPagerAdapter extends PagerAdapter {
    private List
   
   
    
     mViewList;
    private Context mContext;

    public ViewPagerAdapter(List
    
    
     
      mViewList, Context context) {
        this.mViewList = mViewList;
        this.mContext = context;
    }

    @Override
    public int getItemPosition(Object object) {
        return super.getItemPosition(object);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(mViewList.get(position));
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View view = mViewList.get(position);
        container.addView(view);
        return view;
    }

    @Override
    public int getCount() {
        if (mViewList == null)
            return 0;
        return mViewList.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }
}
    
    
   
   
3>为轮播图添加指示器:

首先根据页数添加圆点,然后与ViewPager进行关联;

for (int i = 0; i < pageCount; i++) {
            idotLayout.addView(mInflater.inflate(R.layout.dot, null));
}
默认显示第一个圆点,也就是第一页:

 idotLayout.getChildAt(0).findViewById(R.id.v_dot).setBackgroundResource(R.drawable.dot_selected);
当ViewPager进行滑动时,更改圆点的状态:

在ViewPager的OnPageChangeListener的onPageSelected方法内改变圆点的状态;

// 取消圆点选中
idotLayout.getChildAt(curIndex).findViewById(R.id.v_dot).setBackgroundResource(R.drawable.dot_normal);
 // 圆点选中
idotLayout.getChildAt(position).findViewById(R.id.v_dot).setBackgroundResource(R.drawable.dot_selected);
4>为每一个页面添加图片资源:

//初始化图标资源
for (int i = 0; i < 18; i++) {
     int imageId = getResources().getIdentifier("gift" + i, "mipmap", getPackageName());
     Model model = new Model();
     model.setImage(imageId);
     model.setMoney("520钻石");
     mDataList.add(model);
}
计算页数:

//总的页数=总数/每页数量,并取整
pageCount = (int) Math.ceil(mDataList.size() * 1.0 / pageSize);
将GridView动态添加到ViewPager的数据集合中,在添加每一个GridView时每一个页面的显示个数是一个关键。在这里使用的是把当前页面的序号传递过来,并判断当前数据集合是否满足显示当前的页面进而决定显示个数;

在适配器的getcount()方法中添加一下如下代码:

@Override
    public int getCount() {
        return mDatas.size() > (curIndex + 1) * pageSize ? pageSize : (mDatas.size() - curIndex * pageSize);
    }
下面展示适配器的完整代码:

package com.zxm.giftlistdemo;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.List;

/**
 * Created by ZXM on 2016/9/12.
 */
public class GridViewAdapter extends BaseAdapter {
    private List
   
   
    
     mDatas;
    private LayoutInflater inflater;
    private Context mContext;
    /**
     * 页数下标,从0开始(当前是第几页)
     */
    private int curIndex;
    /**
     * 每一页显示的个数
     */
    private int pageSize = 8;

    public GridViewAdapter(Context context, List
    
    
     
      mDatas, int curIndex) {
        inflater = LayoutInflater.from(context);
        this.mDatas = mDatas;
        this.curIndex = curIndex;
        this.mContext = context;
    }

    /**
     * 先判断数据集的大小是否足够显示满本页?mDatas.size() > (curIndex+1)*pageSize,
     * 如果够,则直接返回每一页显示的最大条目个数pageSize,
     * 如果不够,则有几项返回几,(mDatas.size() - curIndex * pageSize);(也就是最后一页的时候就显示剩余item)
     */
    @Override
    public int getCount() {
        return mDatas.size() > (curIndex + 1) * pageSize ? pageSize : (mDatas.size() - curIndex * pageSize);
    }

    @Override
    public Model getItem(int position) {
        return mDatas.get(position + curIndex * pageSize);
    }

    @Override
    public long getItemId(int position) {
        return position + curIndex * pageSize;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = null;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.item_gridview, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.tv = (TextView) convertView.findViewById(R.id.textView);
            viewHolder.iv = (ImageView) convertView.findViewById(R.id.imageView);
            viewHolder.item_layout = (RelativeLayout) convertView.findViewById(R.id.item_layout);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        /**
         * 在给View绑定显示的数据时,计算正确的position = position + curIndex * pageSize,
         */
        Model model = getItem(position);
        viewHolder.tv.setText(model.getMoney());
        viewHolder.iv.setImageResource(model.getImage());
        if (model.isSelected()){//被选中
            viewHolder.item_layout.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.item_selector));
        }else {
            viewHolder.item_layout.setBackgroundDrawable(null);
        }
        return convertView;
    }


    class ViewHolder {
        public RelativeLayout item_layout;
        public TextView tv;
        public ImageView iv;
    }

}
    
    
   
   
2.Item的选中效果;

这个功能有一下要求:

1>当前Item:重复点击同一个item能够做到状态的切换;

2>选中某一页面的Item,滑动到其他页面,若其他页面未重新选中需要发送的动画,该Item的状态不能改变;

3>选中某一页面的Item,滑动到其他页面,若其他页面重新选中需要发送的动画,该Item的状态取消选中;

我的实现思路是通过一个数组保存创建的GridViewAdapter对象,在ViewPager的监听器OnPageChangeListener的onPageSelected方法内使用notifyDataSeetChanged()方法更改Item的选中状态;

3.详细代码如下:

package com.zxm.giftlistdemo;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private ViewPager viewPager;
    private LinearLayout idotLayout;//知识圆点
    private List
   
   
    
     mPagerList;//页面集合
    private List
    
    
     
      mDataList;//数据集合;
    private LayoutInflater mInflater;

    private Context mContext;
    private int currPage;

    /*总的页数*/
    private int pageCount;
    /*每一页显示的个数*/
    private int pageSize = 8;
    /*当前显示的是第几页*/
    private int curIndex = 0;
    private GridViewAdapter[] arr = new GridViewAdapter[3];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = this;
        initView();
        initValues();
    }


    private void initView() {
        viewPager = (ViewPager) findViewById(R.id.viewpager);
        idotLayout = (LinearLayout) findViewById(R.id.ll_dot);
    }

    private void initValues() {

        mDataList = new ArrayList<>();
        //初始化图标资源
        for (int i = 0; i < 18; i++) {
            int imageId = getResources().getIdentifier("gift" + i, "mipmap", getPackageName());
            Model model = new Model();
            model.setImage(imageId);
            model.setMoney("520钻石");
            mDataList.add(model);
        }

        mInflater = LayoutInflater.from(mContext);
        //总的页数=总数/每页数量,并取整
        pageCount = (int) Math.ceil(mDataList.size() * 1.0 / pageSize);

        //viewpager
        mPagerList = new ArrayList
     
     
      
      ();
        for (int j = 0; j < pageCount; j++) {
            final GridView gridview = (GridView) mInflater.inflate(R.layout.bottom_vp_gridview, viewPager, false);
            final GridViewAdapter gridAdapter = new GridViewAdapter(mContext, mDataList, j);
            gridview.setAdapter(gridAdapter);
            arr[j] = gridAdapter;
            gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
                @Override
                public void onItemClick(AdapterView
      
       parent, View view, int position, long id) {
                    Toast.makeText(mContext, "点击位置position:" + position + "..id:" + id, Toast.LENGTH_SHORT).show();
                MainActivity.this.currPage = finalJ;
                    for (int i = 0; i < mDataList.size(); i++) {
                        Model model = mDataList.get(i);
                        if (i == id) {
                            if (model.isSelected()) {
                                model.setSelected(false);
                            } else {
                                model.setSelected(true);
                            }
                            Log.i("tag", "==点击位置:" + i + "..id:" + id);
                        } else {
                            model.setSelected(false);
//                            Log.i("tag","==位置2:"+i+"..id:"+id);
                        }
                    }
                    Log.i("tag","状态:"+mDataList.toString());
                    gridAdapter.notifyDataSetChanged();
                }
            });
            mPagerList.add(gridview);
        }

        viewPager.setAdapter(new ViewPagerAdapter(mPagerList,MainActivity.this));
        setOvalLayout();
    }

    /**
     * 设置圆点
     */
    public void setOvalLayout() {
        for (int i = 0; i < pageCount; i++) {
            idotLayout.addView(mInflater.inflate(R.layout.dot, null));
        }
        // 默认显示第一页
        idotLayout.getChildAt(0).findViewById(R.id.v_dot)
                .setBackgroundResource(R.drawable.dot_selected);
        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            public void onPageSelected(int position) {
                        arr[0].notifyDataSetChanged();
                        arr[1].notifyDataSetChanged();
                        arr[2].notifyDataSetChanged();

                // 取消圆点选中
                idotLayout.getChildAt(curIndex)
                        .findViewById(R.id.v_dot)
                        .setBackgroundResource(R.drawable.dot_normal);
                // 圆点选中
                idotLayout.getChildAt(position)
                        .findViewById(R.id.v_dot)
                        .setBackgroundResource(R.drawable.dot_selected);
                curIndex = position;
            }

            public void onPageScrolled(int arg0, float arg1, int arg2) {
            }

            public void onPageScrollStateChanged(int arg0) {
            }
        });
    }
}

     
     
    
    
   
   
三、技术难点:

在实现这个功能时,主要的坑就是Item的选中状态的实现;

1.想要改变其他界面的Item的状态使用PagerAdapter的notifyDataSeetChanged()方法是无效的;

这不是PagerAdapter中的Bug,通常情况下,调用notifyDataSetChanged方法会让ViewPager通过Adapter的getItemPosition方法查询一遍所有child view,这种情况下,所有child view位置均为POSITION_NONE,表示所有的child view都不存在,ViewPager会调用destroyItem方法销毁,并且重新生成,加大系统开销,并在一些复杂情况下导致逻辑问题。特别是对于只是希望更新child view内容的时候,造成了完全不必要的开销。

更有效地方法:
更为靠谱的方法是因地制宜,根据自己的需求来实现notifyDataSetChanged的功能,比如,在仅需要对某个View内容进行更新时,在instantiateItem()时,用View.setTag方法加入标志,在需要更新信息时,通过findViewWithTag的方法找到对应的View进行更新即可。


这个方法在项目中我也尝试过,但是效果不太理想,在滑动ViewPager的过程中会有卡涩;

2. 由于在这里,GridView的适配器都是每次添加到ViewPager的时候进行创建,并不能起到作用。所以最终想到了这个方法,通过保存GridView的适配器在ViewPager滑动的时候调用notifyDataSeetChanged()方法,起到了效果。

最后欢迎大家吐槽!


源码链接:直播面板demo

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心灵行者

你的鼓励是我最大的创作动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值