Android项目实战:商城APPday02主页

  • day02
  • 内容
  • 1. 主页面结构分析
  • 2. 请求主页数据和解决数据
  • 3. 主页面适配器
  • 4. 设置横幅广播的适配器
  • 5. 频道适配器
  • 6. 活动适配器
  • 7. 秒杀适配器
  • 8. 推荐适配器
  • 9. 热卖适配器
  • 10. 设置监听 RecyclerView 的位置
  • 11. 商品信息列表类 GoodsInfoActivity
  • 盲区
  • 其他实战
  • 商城
  • 新闻


不否认努力,继续加油!

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

day02

内容

1. 主页面结构分析

  1. 布局分析;
    除去 RadioButton 外,上半啦整体是一个 相对布局
    title + RecyclerView + FloatButton;
  2. 其中 title 用线性布局;利用 DrawableLeft 和 DrawableTop 设置两文本;
  3. RecyclerView 需要对不同显示,设置不同的 6 种适配器;
  4. android购物商城app个人信息界面技术 安卓购物商城界面_移动开发

  5. 初始化布局和设置监听
    需要使用 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);
                }
            });
}
  1. 配置联网路径
//这里创建了一个常量类,其中的常量用静态字符串表示;
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";
}
  1. 使用 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());
    }
}
  1. 生成 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;
  1. 适配器代码
/**
 * 数据对象
 */
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);
    }
}
  1. 使用 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();
        }
    });
}
  1. 设置布局管理者
    此时运行是不会有效果的,因为没有设置布局管理者;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();
                }   
            }
        });
    }
}
  1. 不同的是,这里不用设置布局管理者也可以显示,原因应该是继承的 adapter 的原因;奇怪不……不理解……
  2. 频道适配器 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);
        }
    }
}
  1. 写布局文件;

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);
	        }
	    }
	};
}
  1. 设置横滑 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"/>

android购物商城app个人信息界面技术 安卓购物商城界面_java_02

  1. 设置 RecommendViewHolder;
  2. 设置适配器和监听器;

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);
  1. 实现点击回到顶部的监听方法;
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");
  1. 解析数据并设置商品详情页面数据
  2. 使用 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.