Android-主页实现 6种适配器的适配 & 抢购页面实现—购物商场实战项目02


不否认努力,继续加油!

学习整理重点、盲区,笔记如下:干干巴巴,麻麻赖赖,一点都不圆润……
源码 已上传至集哈:ShoppingMall.
https://github.com/SmileAlfred/ShoppingMall

day02

内容

1. 主页面结构分析

  1. 布局分析;
    除去 RadioButton 外,上半啦整体是一个 相对布局
    title + RecyclerView + FloatButton;

  2. 其中 title 用线性布局;利用 DrawableLeft 和 DrawableTop 设置两文本;

  3. RecyclerView 需要对不同显示,设置不同的 6 种适配器;
    在这里插入图片描述

  4. 初始化布局和设置监听
    需要使用 view 去实例化控件,不可以直接 findViewById();

    @Override
    public View initView() {
        View view = View.inflate(mContext, R.layout.fragment_home, null);
        rvHome = (RecyclerView) view.findViewById(R.id.rv_home);
        ib_top = (ImageView) view.findViewById(R.id.ib_top);
        tv_search_home = (TextView) view.findViewById(R.id.tv_search_home);
        tv_message_home = (TextView) view.findViewById(R.id.tv_message_home);
        //设置点击事件
        initListener();
        return view;
    }
    

2. 请求主页数据和解决数据

  1. 使用 OkHttpUtil s 请求网络

    添加依赖:implementation 'com.github.xxl6097:okhttputils:2.4.1'
    添加联网权限:
    
    private void getDataFromNet() {
        String url = Constants.HOME_URL;
        OkHttpUtils.get()
                .url(url)
                .build()
                .execute(new StringCallback() {
                    /**
                     * 当请求失败的时候回调
                     */
                    @Override
                    public void onError(Call call, Exception e) {
                        Log.e(TAG, "首页请求失败==" + e.getMessage());
                    }
                    /**
                     * 当联网成功的时候回调
                     */
                    @Override
                    public void onResponse(Call call, String s) {
                        Log.e(TAG, "首页请求成功==" + s);
                        //解析数据
                        processData(s);
                    }
                });
    }
    
  2. 配置联网路径

    //这里创建了一个常量类,其中的常量用静态字符串表示;
    public class Constants {
        public static String BASE_URL = "http://192.168.0.9:8080/atguigu";
        /**
         * 主页面的路径
         */
        public static String HOME_URL  = BASE_URL+"/json/HOME_URL.json";
        /**
         * 图片的基本路径
         */
        public static String BASE_URL_IMAGE  = BASE_URL+"/img";
    }
    
  3. 使用 fastjson(By Alibaba) 解析数据

    添加依赖:implementation 'com.alibaba:fastjson:1.2.68'
    
    private void processData(String json) {
    	if (!TextUtils.isEmpty(json)) {
        	ResultBeanData resultBeanData = JSON.parseObject(json, ResultBeanData.class);
        	resultBean = resultBeanData.getResult();
        	Log.e(TAG, "解析成功==" + resultBean.getHot_info().get(0).getName());
        }
    }
    
  4. 生成 JeanBean
    使用插件 GsonFromat 生成 Bean 对象;

3. 主页面适配器

  1. 选择 RecyclerView,因为其中可以使用不同种类的多种 adapter;首页有六种不同的效果,分别是如下,广告条,分类,ViewPager,秒杀栏,三栏的 RecyclerView,两栏的 RecyclerView;
    在这里插入图片描述

  2. 六种类型的 ViewHolder ,设置类型,

    /**
     * 广告条幅类型、频道类型、活动类型、秒杀类型、推荐类型、热卖;
     */
    public static final int BANNER = 0;
    public static final int CHANNEL = 1;
    public static final int ACT = 2;
    public static final int SECKILL = 3;
    public static final int RECOMMEND = 4;
    public static final int HOT = 5;
    /**
     * 当前类型
     */
    private int currentType = BANNER;
    
  3. 适配器代码

    /**
     * 数据对象
     */
    private ResultBean resultBean;
    private Context mContext;
    private LayoutInflater mLayoutInflater;
    @Override
    public int getItemCount() {
        //以后做完后改成6,现在只实现横幅广告,暂时写1 
        return 1;
    }
    @Override
    public int getItemViewType(int position) {
        switch (position) {
            case BANNER:
                currentType = BANNER;
                break;
            case CHANNEL:
                currentType = CHANNEL;
                break;
            case ACT:
                currentType = ACT;
                break;
            case SECKILL:
                currentType = SECKILL;
                break;
            case RECOMMEND:
                currentType = RECOMMEND;
                break;
            case HOT:
                currentType = HOT;
                break;
        }
        return currentType;
    }
    public HomeRecycleAdapter(Context mContext, ResultBean resultBean) {
        this.mContext = mContext;
        this.resultBean = resultBean;
        mLayoutInflater = LayoutInflater.from(mContext);
    }
    

4. 设置横幅广播的适配器

  1. 关联使用 Banner 库;
    实现效果:切换页面像手风琴一样的推动;
    在这里插入图片描述

  2. 设置适配器继承自 RecyclerView.Adapter;

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == BANNER) {
            return new BannerViewHolder(mLayoutInflater.inflate(R.layout.banner_viewpager, null), mContext, resultBean);
        }
        return null;
    }
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (getItemViewType(position) == BANNER) {
            BannerViewHolder bannerViewHolder = (BannerViewHolder) holder;
            //设置数据Banner的数据
            bannerViewHolder.setData(resultBean.getBanner_info());
        }
    }
    /**
     * 设置适配器
     */
    class BannerViewHolder extends RecyclerView.ViewHolder {
        public Banner banner;
        public Context mContext;
        public ResultBean resultBean;
        public BannerViewHolder(View itemView, Context mContext, ResultBean resultBean) {
            super(itemView);
            banner = (Banner) itemView.findViewById(R.id.banner);
            this.mContext = mContext;
            this.resultBean = resultBean;
        }
        public void setData(final List<ResultBean.BannerInfoBean> banner_info) {
            setBannerData(banner_info);
        }
    }
    
  3. 使用 Banner 库

    private void setBannerData(final List<ResultBean.BannerInfoBean> banner_info) {
        //设置循环指标点
        banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR);
        //如果想用自己项目的图片加载,就自定义图片加载框架
        List<String> imageUris = new ArrayList<>();
        for (int i = 0; i < resultBean.getBanner_info().size(); i++) {
            imageUris.add(resultBean.getBanner_info().get(i).getImage());
        }
        // 设置类似手风琴动画
        banner.setBannerAnimation(Transformer.Accordion);
        //设置加载图片
        banner.setImages(imageUris, new OnLoadImageListener() {
            @Override
            public void OnLoadImage(ImageView view, Object url) { 
                Glide.with(mContext).load(Constants.Base_URl_IMAGE + url).into(view);
            }
        });
        //设置点击事件 
        banner.setOnBannerClickListener(new OnBannerClickListener() {
            @Override
            public void OnBannerClick(int position) {
            	Toast.makeText(mContext, "position==" + position, Toast.LENGTH_SHORT).show();
            }
        });
    }
    
  4. 设置布局管理者
    此时运行是不会有效果的,因为没有设置布局管理者;GridLayoutManager manager = new GridLayoutManager(mContext, 1);

    首页设置完适配器后,要及时添加如上布局管理者,这里选择GridLayout 而不是选择 RelativeLayout 和 LinearLayout;

5. 频道适配器

  1. 设置适配器继承自 BaseAdapter;
    实现效果:
    在这里插入图片描述

  2. 和 Banner 适配器类似

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == BANNER) {
            return new BannerViewHolder(mLayoutInflater.inflate(R.layout.banner_viewpager, null), mContext, resultBean);
        }else if (viewType == CHANNEL) { 
        	return new ChannelViewHolder(mLayoutInflater.inflate(R.layout.channel_item, null), mContext); 
        	}
        return null;
    }
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (getItemViewType(position) == BANNER) {
            BannerViewHolder bannerViewHolder = (BannerViewHolder) holder;
            //设置数据Banner的数据
            bannerViewHolder.setData(resultBean.getBanner_info());
        }else if (getItemViewType(position) == CHANNEL) { 
        	ChannelViewHolder channelViewHolder = (ChannelViewHolder) holder; 
        	channelViewHolder.setData(resultBean.getChannel_info());
    }
    /**
     * 设置适配器
     */
    class ChannelViewHolder extends RecyclerView.ViewHolder {
        public GridView gvChannel;
        public Context mContext;
        public ChannelViewHolder(View itemView, Context mContext) {
            super(itemView);
            gvChannel = (GridView) itemView.findViewById(R.id.gv_channel);
            this.mContext = mContext;
        }
        public void setData(final List<ResultBean.ChannelInfoBean> channel_info) {
            gvChannel.setAdapter(new ChannelAdapter(mContext, channel_info)); 
            //点击事件 gvChannel.setOnItemClickListener(new
            AdapterView.OnItemClickListener() {
                @Override public void onItemClick (AdapterView < ? > parent, View view,int position,
                long id){
                    if (position <= 8) {
                        Toast.makeText(mContext, "position==" + position, Toast.LENGTH_SHORT).show();
                    }   
                }
            });
        }
    }
    
  3. 不同的是,这里不用设置布局管理者也可以显示,原因应该是继承的 adapter 的原因;奇怪不……不理解……

  4. 频道适配器 ChannelAdapter

    public class ChannelAdapter extends BaseAdapter {
        private Context mContext;
        private List<ResultBean.ChannelInfoBean> channel_info;
        public ChannelAdapter(Context mContext, List<ResultBean.ChannelInfoBean> channel_info) {
            this.mContext = mContext;
            this.channel_info = channel_info;
        }
        @Override
        public int getCount() {
            return channel_info == null ? 0 : channel_info.size();
        }
        @Override
        public Object getItem(int position) {
            return channel_info.get(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holer;
            if (convertView == null) {
                convertView = View.inflate(mContext, R.layout.item_channel, null);
                holer = new ViewHolder(convertView);
                convertView.setTag(holer);
            } else {
                holer = (ViewHolder) convertView.getTag();
            }
            ResultBean.ChannelInfoBean channelInfoBean = channel_info.get(position);
            holer.tvChannel.setText(channelInfoBean.getChannel_name());
            Glide.with(mContext).load(Constants.Base_URl_IMAGE + channelInfoBean.getImage()).into(holer.ivChannel);
            return convertView;
        }
        static class ViewHolder {
            @Bind(R.id.iv_channel)
            ImageView ivChannel;
            @Bind(R.id.tv_channel)
            TextView tvChannel;
            ViewHolder(View view) {
                ButterKnife.bind(this, view);
            }
        }
    }
    
  5. 写布局文件;

6. 活动适配器

  1. 写布局,实现如下广告条效果:在这里插入图片描述

  2. 设置适配器;这里用到的是 PagerAdapter;

    class ActViewHolder extends RecyclerView.ViewHolder {
        public ViewPager actViewPager;
        public Context mContext;
        public ActViewHolder(View itemView, Context mContext) {
            super(itemView);
            actViewPager = (ViewPager) itemView.findViewById(R.id.act_viewpager);
            this.mContext = mContext;
        }
        public void setData(final List<ResultBean.ActInfoBean> data) {
            //设置每个页面的间距 
            actViewPager.setPageMargin(20); //>=3 
            actViewPager.setOffscreenPageLimit(3);
            //第三方库实现页面切换的不同动画:implementation 'com.zhy:magic-viewpager:1.0.1'
            actViewPager.setPageTransformer(true, new AlphaPageTransformer(new ScaleInTransformer()));
            actViewPager.setAdapter(new PagerAdapter() {
                @Override
                public int getCount() {
                    return data.size();
                }
                @Override
                public boolean isViewFromObject(View view, Object object) {
                    return view == object;
                }
                @Override
                public Object instantiateItem(ViewGroup container, int position) {
                    ImageView view = new ImageView(mContext);
                    view.setScaleType(ImageView.ScaleType.FIT_XY);
                    //绑定数据 
                    Glide.with(mContext).load(Constants.Base_URl_IMAGE + data.get(position).getIcon_url()).into(view)
                    container.addView(view);
                    return view;
                }
                @Override
                public void destroyItem(ViewGroup container, int position, Object object) {
                    container.removeView((View) object);
                }
            });
            //点击事件 
            actViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset,int positionOffsetPixels) {
                }
                @Override
                public void onPageSelected(int position) {
                    Toast.makeText(mContext, "position:" + position, Toast.LENGTH_SHORT).show();
                }
                @Override
                public void onPageScrollStateChanged(int state) {
                }
            });
        }
    }
    

7. 秒杀适配器

  1. 写布局,实现如下效果:上边时横向的linear layout;下面是横滑的 RecyclerView;
    在这里插入图片描述

  2. 设置 SeckillViewHolder ;

    class SeckillViewHolder extends RecyclerView.ViewHolder {
    	//与上述类似,省略相同方法;……
    	public void setData(final ResultBeanData.ResultBean.SeckillInfoBean seckill_info) {
    	    //1.设置数据:文本和RecyclerView的数据
    	    adapter = new SeckillRecyclerViewAdapter(mContext, seckill_info.getList());
    	    rv_seckill.setAdapter(adapter);
    	    //2.设置布局管理器
    	    rv_seckill.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
    	    //3.设置item的点击事件
    	    adapter.setOnSeckillRecyclerView(new SeckillRecyclerViewAdapter.OnSeckillRecyclerView() {
    	        @Override
    	        public void onItemClick(int position) {
    	            Toast.makeText(mContext, "秒杀" + position, Toast.LENGTH_SHORT).show();
    	        }
    	    });
    	    //4.秒杀倒计时 -毫秒
    	    dt = Integer.valueOf(seckill_info.getEnd_time()) - Integer.valueOf(seckill_info.getStart_time());
    	    handler.sendEmptyMessageDelayed(0, 1000);
    	}
    	//5.设置倒计时
    	private Handler handler = new Handler() {
    	    @Override
    	    public void handleMessage(Message msg) {
    	        super.handleMessage(msg);
    	        dt = dt - 1000;
    	        SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
    	        String time = formatter.format(new Date(dt));
    	        tv_time_seckill.setText(time);
    	        handler.removeMessages(0);
    	        handler.sendEmptyMessageDelayed(0, 1000);
    	        if (dt <= 0) {
    	            //把消息移除
    	            handler.removeCallbacksAndMessages(null);
    	        }
    	    }
    	};
    }
    
  3. 设置横滑 RecyclerView 的适配器和监听器;

    public class SeckillRecyclerViewAdapter extends RecyclerView.Adapter<SeckillRecyclerViewAdapter.ViewHodler> {
        private final List<ResultBeanData.ResultBean.SeckillInfoBean.ListBean> list;
        private final Context mContext;
    
        public SeckillRecyclerViewAdapter(Context mContext, List<ResultBeanData.ResultBean.SeckillInfoBean.ListBean> list) {
            this.list = list;
            this.mContext = mContext;
        }
    
        @Override
        public ViewHodler onCreateViewHolder(ViewGroup parent, int viewType) {
            View itemView = View.inflate(mContext, R.layout.item_seckill, null);
            return new ViewHodler(itemView);
        }
    
        @Override
        public void onBindViewHolder(ViewHodler holder, int position) {
            //1.根据位置得到对应的数据
            ResultBeanData.ResultBean.SeckillInfoBean.ListBean listBean = list.get(position);
            //2.绑定数据
            Glide.with(mContext).load(Constants.BASE_URL_IMAGE + listBean.getFigure()).into(holder.iv_figure);
            holder.tv_cover_price.setText(listBean.getCover_price());
            holder.tv_origin_price.setText(listBean.getOrigin_price());
        }
    
        @Override
        public int getItemCount() {
            return list.size();
        }
    
        class ViewHodler extends RecyclerView.ViewHolder {
            private ImageView iv_figure;
            private TextView tv_cover_price;
            private TextView tv_origin_price;
    
            public ViewHodler(View itemView) {
                super(itemView);
                iv_figure = (ImageView) itemView.findViewById(R.id.iv_figure);
                tv_cover_price = (TextView) itemView.findViewById(R.id.tv_cover_price);
                tv_origin_price = (TextView) itemView.findViewById(R.id.tv_origin_price);
                tv_origin_price.getPaint().setFlags(Paint. STRIKE_THRU_TEXT_FLAG );//给原价 TextView 添加横滑线
    
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Toast.makeText(mContext, "秒杀="+getLayoutPosition(), Toast.LENGTH_SHORT).show();
                        if (onSeckillRecyclerView != null) {
                            onSeckillRecyclerView.onItemClick(getLayoutPosition());
                        }
                    }
                });
            }
        }
    
        /**
         * 监听器
         */
        public interface OnSeckillRecyclerView {
            //当某条被点击的时候回调
            public void onItemClick(int position);
        }
    
        private OnSeckillRecyclerView onSeckillRecyclerView;
        //设置item的监听
        public void setOnSeckillRecyclerView(OnSeckillRecyclerView onSeckillRecyclerView) {
            this.onSeckillRecyclerView = onSeckillRecyclerView;
        }
    }
    

8. 推荐适配器

  1. 写布局,实现如下效果:上边时横向的 LinearLayout;下面是三列形式的 GridView;

    <GridView
        android:id="@+id/gv_recommend"
        android:layout_width="match_parent"
        android:layout_height="380dp"
        android:numColumns="3"/>
    

    在这里插入图片描述

  2. 设置 RecommendViewHolder;

  3. 设置适配器和监听器;

9. 热卖适配器

  1. 写布局,实现如下效果:上边时横向的 LinearLayout;下面是两列形式的 GridView;
    在这里插入图片描述
  2. 设置 RecommendViewHolder;
  3. 设置适配器和监听器;

10. 设置监听 RecyclerView 的位置

  1. 隐藏和显示回到顶部按钮

    实现目的:当页面滑动不在首页时,右下角的 float button 显示,点击后回到顶部,而后隐藏;

    //HomeFragment.java 中 processData();
    adapter = new HomeFragmentAdapter(mContext, resultBean);
    rvHome.setAdapter(adapter);
    GridLayoutManager manager = new GridLayoutManager(mContext, 1);
    //设置跨度大小监听
    manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
        @Override
        public int getSpanSize(int position) {
            if (position <= 3) {
                ib_top.setVisibility(View.GONE);
            } else {
                ib_top.setVisibility(View.VISIBLE);
            }
            //只能返回1
            return 1;
        }
    });
    //设置布局管理者
    rvHome.setLayoutManager(manager);
    
  2. 实现点击回到顶部的监听方法;

    ib_top.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            rvHome.scrollToPosition(0);
        }
    

11. 商品信息列表类 GoodsInfoActivity

  1. 商品信息列表类页面实现分析
    布局分成三部分:
    1:标题栏
    2:分割线
    3:帧布居
    a: 线性布局;里面用 ScrollViewContainer 嵌套两个 ScrollView
    b: 线性布局;客服联系,收藏,购物车等
    c: 更多;分享, 搜索,首页等

  2. 写布局 activity_goods_info.xml;

  3. 布局的实例化和设置点击事件;

  4. 商品详情页面的数据传递和接收;

    传递对象时,要将其序列化;

    //传递对象
    Intent intent = new Intent(mContext, GoodsInfoActivity.class);
    intent.putExtra(GOODS_BEAN,goodsBean);
    mContext.startActivity(intent);
    //取出intent 
    Intent intent = getIntent(); 
    goods_bean = (GoodsBean) intent.getSerializableExtra("goods_bean");
    
  5. 解析数据并设置商品详情页面数据

  6. 使用 WebView 加载设置 商品详情 数据

盲区

  1. 声明:本博客根据尚硅谷项目实战: 硅谷商城.学习整理;
  2. 对于 okhttputils 一些封装工具,用的不熟悉,尤其是在Json数据解析时间,接下来会深入学习,并会同步更新详细笔记;
  3. 在设置 RadioButton 的监听器时报错,内容显示 Butterknife 和监听冲突,最后还是老老实实 findViewById(),解了,不过应该对 Butterknife 再研究一下;
  4. 设置适配器的时候,出现了 BaseAdapter 、 RecyclerView.Adapter 和 PagerAdapter;使用 RecyclerView.Adapter 时要写布局管理者;对于这些适配器还不了解;
  5. 对于加载商品详情页面时,对于其 json 数据的解析还是存在瑕疵;
  6. 加油!奥里给!

其他实战

商城

  1. day01
    第一节学习笔记:链接: 商城APP01—框架搭建.

  2. day02
    第二节学习笔记:链接: 商城APP02—主页实现.

  3. day03
    第三节学习笔记:链接: 商城APP03—购物车实现.

新闻

Android项目实战——新闻APP 学习笔记:链接: 新闻APP.

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

liusaisaiV1

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

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

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

打赏作者

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

抵扣说明:

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

余额充值