Android項目實戰:商城APPday02主頁
不否認努力,繼續加油!
學習整理重點、盲區,筆記如下:乾乾巴巴,麻麻賴賴,一點都不圓潤……
源碼 已上傳至集哈:ShoppingMall.
https://github.com/SmileAlfred/ShoppingMall
day02
內容
1. 主頁面結構分析
-
佈局分析;
除去 RadioButton 外,上半啦整體是一個 相對佈局,
title + RecyclerView + FloatButton; -
其中 title 用線性佈局;利用 DrawableLeft 和 DrawableTop 設置兩文本;
-
RecyclerView 需要對不同顯示,設置不同的 6 種適配器;
-
初始化佈局和設置監聽
需要使用 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. 請求主頁數據和解決數據
-
使用 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); } }); }
-
配置聯網路徑
//這裏創建了一個常量類,其中的常量用靜態字符串表示; 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"; }
-
使用 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()); } }
-
生成 JeanBean
使用插件 GsonFromat 生成 Bean 對象;
3. 主頁面適配器
-
選擇 RecyclerView,因爲其中可以使用不同種類的多種 adapter;首頁有六種不同的效果,分別是如下,廣告條,分類,ViewPager,秒殺欄,三欄的 RecyclerView,兩欄的 RecyclerView;
-
六種類型的 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;
-
適配器代碼
/** * 數據對象 */ 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. 設置橫幅廣播的適配器
-
關聯使用 Banner 庫;
實現效果:切換頁面像手風琴一樣的推動;
-
設置適配器繼承自 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); } }
-
使用 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(); } }); }
-
設置佈局管理者
此時運行是不會有效果的,因爲沒有設置佈局管理者;GridLayoutManager manager = new GridLayoutManager(mContext, 1);
首頁設置完適配器後,要及時添加如上佈局管理者,這裏選擇GridLayout 而不是選擇 RelativeLayout 和 LinearLayout;
5. 頻道適配器
-
設置適配器繼承自 BaseAdapter;
實現效果:
-
和 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(); } } }); } }
-
不同的是,這裏不用設置佈局管理者也可以顯示,原因應該是繼承的 adapter 的原因;奇怪不……不理解……
-
頻道適配器 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); } } }
-
寫佈局文件;
6. 活動適配器
-
寫佈局,實現如下廣告條效果:
-
設置適配器;這裏用到的是 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. 秒殺適配器
-
寫佈局,實現如下效果:上邊時橫向的linear layout;下面是橫滑的 RecyclerView;
-
設置 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); } } }; }
-
設置橫滑 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. 推薦適配器
-
寫佈局,實現如下效果:上邊時橫向的 LinearLayout;下面是三列形式的 GridView;
<GridView android:id="@+id/gv_recommend" android:layout_width="match_parent" android:layout_height="380dp" android:numColumns="3"/>
-
設置 RecommendViewHolder;
-
設置適配器和監聽器;
9. 熱賣適配器
- 寫佈局,實現如下效果:上邊時橫向的 LinearLayout;下面是兩列形式的 GridView;
- 設置 RecommendViewHolder;
- 設置適配器和監聽器;
10. 設置監聽 RecyclerView 的位置
-
隱藏和顯示回到頂部按鈕
實現目的:當頁面滑動不在首頁時,右下角的 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);
-
實現點擊回到頂部的監聽方法;
ib_top.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { rvHome.scrollToPosition(0); }
11. 商品信息列表類 GoodsInfoActivity
-
商品信息列表類頁面實現分析
佈局分成三部分:
1:標題欄
2:分割線
3:幀布居
a: 線性佈局;裏面用 ScrollViewContainer 嵌套兩個 ScrollView
b: 線性佈局;客服聯繫,收藏,購物車等
c: 更多;分享, 搜索,首頁等 -
寫佈局 activity_goods_info.xml;
-
佈局的實例化和設置點擊事件;
-
商品詳情頁面的數據傳遞和接收;
傳遞對象時,要將其序列化;
//傳遞對象 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");
-
解析數據並設置商品詳情頁面數據
-
使用 WebView 加載設置 商品詳情 數據
盲區
- 聲明:本博客根據尚硅谷項目實戰: 硅谷商城.學習整理;
- 對於 okhttputils 一些封裝工具,用的不熟悉,尤其是在Json數據解析時間,接下來會深入學習,並會同步更新詳細筆記;
- 在設置 RadioButton 的監聽器時報錯,內容顯示 Butterknife 和監聽衝突,最後還是老老實實 findViewById(),解了,不過應該對 Butterknife 再研究一下;
- 設置適配器的時候,出現了 BaseAdapter 、 RecyclerView.Adapter 和 PagerAdapter;使用 RecyclerView.Adapter 時要寫佈局管理者;對於這些適配器還不瞭解;
- 對於加載商品詳情頁面時,對於其 json 數據的解析還是存在瑕疵;
- 加油!奧裏給!
其他實戰
商城
-
day01
第一節學習筆記:鏈接: 商城APP01—框架搭建. -
day02
第二節學習筆記:鏈接: 商城APP02—主頁實現. -
day03
第三節學習筆記:鏈接: 商城APP03—購物車實現.
新聞
Android項目實戰——新聞APP 學習筆記:鏈接: 新聞APP.