黑马外卖笔记(三)

本文介绍了Android开发中如何利用bottomSheet实现底部菜单效果,以及使用stickylistheaders实现列表分组和头部固定,详细讲解了相关控件的使用、布局配置、点击事件处理和数据加载。同时,还涵盖了商铺页面的UI设计,包括BottomSheet的运用和购物车功能的实现,如添加、删除购物车商品的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 掌握bottomSheet,开发购物车

项目效果

 

控件运行效果

 

[开源控件库]https://github.com/Flipboard/bottomsheet

第三方开源控件库,可以快速实现类似底部菜单的效果(类似安全卫士-归属地风格选择Dialog)

使用步骤

>1.依赖

compile'com.flipboard:bottomsheet-commons:1.5.1'
compile 'com.flipboard:bottomsheet-core:1.5.1'

>2.布局页面内容

layout/activity_main.xml

<?xml version="1.0"encoding="utf-8"?>
<com.flipboard.bottomsheet.BottomSheetLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/bottom_sheet_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
>
        <Button
            android:onClick="show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="三"
/>
    </LinearLayout>
</com.flipboard.bottomsheet.BottomSheetLayout>

>3.布局弹出内容

layout/pop_sheet.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#FFF000"
    android:orientation="vertical"
    tools:context="com.itheima.app_bottom.MainActivity"
>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="条目一"
/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="条目二"
/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="条目三"
/>
</LinearLayout>

>4.编写显示与隐藏逻辑

public classMainActivityextends AppCompatActivity {

    privateBottomSheetLayoutbottomSheetLayout;
    privateView popView;

    @Override
    protected voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //查找控件
        
bottomSheetLayout= (BottomSheetLayout) findViewById(R.id.bottom_sheet_layout);
    }

    public voidshow(View view) {
        //判断弹出内容是否可见
        
if(bottomSheetLayout.isSheetShowing()) {
            //可见则隐藏
            
bottomSheetLayout.dismissSheet();
        } else {
            if(popView== null) {
                popView= LayoutInflater.from(this).inflate(R.layout.pop_sheet,bottomSheetLayout,false);
            }
            //不可见则显示 ,对popView进行是否为空判断可以减少view的创建
            
bottomSheetLayout.showWithSheetView(popView);
        }
    }
}

 

2. 掌握stickylistheaders,使用tabs滑动固定

运行效果

 

 

【开源控件库】https://github.com/emilsjolander/StickyListHeaders

将元素按照typeId进行组,相同typeId的元素在一个分组。

组视图可以上滑到达顶部固定住(类似联系人效果)

>1.依赖

compile'se.emilsjolander:stickylistheaders:2.7.0'

>2.布局UI

layout/activity_main.xml

<?xml version="1.0"encoding="utf-8"?>
<se.emilsjolander.stickylistheaders.StickyListHeadersListViewxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/stick_headers_lv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
/>

layout/item_header.xml

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.itheima.appstickyheader.MainActivity"
>
<TextView
    android:id="@+id/title"
    android:layout_width="match_parent"
    android:text="标题"
    android:padding="10dp"
    android:background="#FFF000"
    android:layout_height="wrap_content"
/>
</RelativeLayout>

layout/item.xml

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.itheima.appstickyheader.MainActivity"
>
<TextView
    android:id="@+id/text"
    android:layout_width="match_parent"
    android:text="条目"
    android:textSize="22sp"
    android:padding="10dp"
    android:layout_height="wrap_content"
/>
</RelativeLayout>

>3.创建带有typeId的记录

//数据模型
public classInfo {
    private inttypeId;
    privateString typeName;
    privateString content;
    //typeId相同的id代表同一个组的元素
    //typeName组名
    //content元素名
    
publicInfo(inttypeId, String typeName, String content) {
        this.typeId= typeId;
        this.typeName= typeName;
        this.content= content;
    }省略get/set

>4使用适配器进行初始化

public classMainActivityextends AppCompatActivity {

    @InjectView(R.id.stick_headers_lv)
    StickyListHeadersListViewstickHeadersLv;
    privateList<Info>mData = null;
    @Override
    protected voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.inject(this);
        mData= new ArrayList<>();
        for(inti = 0; i <5; i++) {
            for(intj = 0; j <10; j++) {
                mData.add(newInfo(i, "组名" + i,"成员" + i + "--"+ j));
            }
        }
        MyAdapter adapter =new MyAdapter();
        stickHeadersLv.setAdapter(adapter);
    }

>5.实现适配器

private classMyAdapterextends BaseAdapter implements StickyListHeadersAdapter {
    //组
    
@Override
    publicView getHeaderView(intposition, View convertView, ViewGroup parent) {
        if(convertView ==null) {
            convertView = View.inflate(parent.getContext(), R.layout.item_header,null);
        }
        TextView text = (TextView) convertView.findViewById(R.id.title);
        Info info =mData.get(position);
        text.setText(info.getTypeName());
        returnconvertView;
    }
    //元素
    
@Override
    publicView getView(intposition, View convertView, ViewGroup parent) {
        if(convertView ==null) {
            convertView = View.inflate(parent.getContext(), R.layout.item,null);
        }
        TextView text = (TextView) convertView.findViewById(R.id.text);
        Info info =mData.get(position);
        text.setText(info.getContent());
        returnconvertView;
    }
    //按typeid分组
    
@Override
    public longgetHeaderId(intposition) {
        returnmData.get(position).getTypeId();
    }

    @Override
    public intgetCount() {
        returnmData.size();
    }

 

3. 进入到商铺页面,选餐

3.1. 给条目添加点击事件,Intent打开BusinessActivity

 

 

com.itheima.app_.ui.adapter.HeaderAdapter

>1.添加点击事件,意图打开页面

com.itheima.app_.ui.adapter.HeaderAdapter#onBindViewHolder方法中

//添加点击事件跳转到商铺页面
hd.itemView.setOnClickListener(newView.OnClickListener() {
    @Override
    public voidonClick(View v) {

        Intent intent=newIntent(v.getContext(),BussinessActivity.class);
        intent.putExtra("item",item);
        v.getContext().startActivity(intent);
    }
});

注意事项:

Intent传递javaBean要求这个对象序列化

BodyInfo序列化

SellerInfo序列化

 

3.2. 创建BusinessActivity界面

>1.配置

<activityandroid:name=".ui.activity.BussinessActivity"/>

>2.创建页面

public classBussinessActivityextends BaseActivity {
    @Override
    protected voidonCreate(@NullableBundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //给手机状态栏着色
        
initSystemBar()

}

>3.布局UI

3.3. 整体界面UI分析(引入BottomSheet)

   //底部弹出窗体
    
compile'com.flipboard:bottomsheet-commons:1.5.1'
    
compile'com.flipboard:bottomsheet-core:1.5.1'

 

layout/activity_bussiness.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:fitsSystemWindows="true"
    android:clipToPadding="false"
>
    <!--内容-->
    
<com.flipboard.bottomsheet.BottomSheetLayout
        android:id="@+id/bottom_sheet_layout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
>
        <!--BottomSheetLayout的子元素必须为1-->
           
<LinearLayout
               android:layout_width="match_parent"
               android:orientation="vertical"
               android:layout_height="match_parent"
>
                <!--标题-->
              
<includelayout="@layout/include_titlebar"/>
                <!--商品评价商家-->
               
<includelayout="@layout/include_tabs_viewpager"/>
           </LinearLayout>
    </com.flipboard.bottomsheet.BottomSheetLayout>
    <!--底部-->
    
<includelayout="@layout/include_bottom"/>
</LinearLayout>

可以使用include知识点,将布局好的内容引入,这样页面结构更清析

3.4. 使用include引入标题

layout/include_titlebar.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#f6f89191"
    android:orientation="horizontal"
    android:paddingBottom="10dp"
    android:paddingTop="25dp"
>
    <ImageButton
        android:id="@+id/ib_back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        android:background="@mipmap/ic_back"
/>
    <TextView
        android:id="@+id/tv_title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_weight="1"
        android:maxLines="1"
        android:text="标题--"
        android:textColor="#fff"
        android:textSize="20sp"
        android:textStyle="bold"
/>

    <ImageButton
        android:id="@+id/ib_menu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginRight="10dp"
        android:background="@mipmap/ic_menu"
/>
</LinearLayout>

3.5. 使用include引入tablayoutviewpager

layout/include_tabs_viewpager.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
>
    <android.support.design.widget.TabLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabIndicatorColor="#00f"
        app:tabIndicatorHeight="4dp"
        app:tabSelectedTextColor="#00f"
        app:tabTextColor="#000"
/>
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
/>
</LinearLayout>

属性解释

app:tabIndicatorColor="#00f"  tab底部选中的颜色标识

app:tabIndicatorHeight="4dp" 标识的高度

app:tabSelectedTextColor="#00f"  选中tab文字的颜色

app:tabTextColor="#000"   没有选中tab文字的颜色

 

3.6. 使用include引入底部购物车

layout/include_shop_cart.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bottom"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#aa000000"
    android:clickable="true"
    android:gravity="center_vertical"
    android:onClick="onClick"
    android:orientation="horizontal"
>
    <RelativeLayout
        android:layout_width="50dp"
        android:layout_height="match_parent"
>

        <ImageView
            android:id="@+id/img_cart"
            android:layout_width="32dp"
            android:layout_height="32dp"
            android:layout_centerInParent="true"
            android:src="@mipmap/icon_cart"
/>

        <TextView
            android:id="@+id/tv_select_num"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_marginRight="5dp"
            android:layout_marginTop="5dp"
            android:background="@drawable/circle_red"
            android:gravity="center"
            android:text="1"
            android:textColor="#fff"
            android:textSize="12sp"
            android:visibility="gone"
/>
    </RelativeLayout>

    <TextView
        android:id="@+id/tv_count_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="2dp"
        android:gravity="center_vertical"
        android:text="¥0"
        android:textColor="#fff"
        android:textSize="14sp"
/>

    <TextView
        android:id="@+id/tv_delivery_fee"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_marginRight="5dp"
        android:layout_weight="1"
        android:gravity="center"
        android:text="另需配送费¥4"
        android:textColor="#fff"
        android:textSize="14sp"
/>

    <TextView
        android:id="@+id/tv_send_price"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginRight="10dp"
        android:gravity="center"
        android:text="¥100元起送"
        android:textColor="#fff"
        android:textSize="14sp"
/>

    <TextView
        android:id="@+id/tv_submit"
        android:layout_width="90dp"
        android:layout_height="match_parent"
        android:background="#22c222"
        android:clickable="true"
        android:gravity="center"
        android:onClick="onClick"
        android:text="去结算"
        android:textColor="#fff"
        android:textSize="18sp"
        android:visibility="gone"
/>
</LinearLayout>

 

3.7. 使用BusinessViewHolder缓存所有控件

以下代码使用butterknife自动生成不需要手动编码

把所有元素放到hd,方便以后使用减少activity代码

//页面控件的缓存BusinessViewHolder
static classBusinessViewHolder {
    @InjectView(R.id.ib_back)
    ImageButton ibBack;
    @InjectView(R.id.tv_title)
    TextView tvTitle;
    @InjectView(R.id.ib_menu)
    ImageButton ibMenu;
    @InjectView(R.id.tab_layout)
    TabLayout tabLayout;
    @InjectView(R.id.viewpager)
    ViewPager viewpager;
    @InjectView(R.id.bottom_sheet_layout)
    BottomSheetLayoutbottomSheetLayout;
    @InjectView(R.id.img_cart)
    ImageView imgCart;
    @InjectView(R.id.tv_select_num)
    TextView tvSelectNum;
    @InjectView(R.id.tv_count_price)
    TextView tvCountPrice;
    @InjectView(R.id.tv_delivery_fee)
    TextView tvDeliveryFee;
    @InjectView(R.id.tv_send_price)
    TextView tvSendPrice;
    @InjectView(R.id.tv_submit)
    TextView tvSubmit;
    @InjectView(R.id.bottom)
    LinearLayout bottom;

    BusinessViewHolder(View view) {
        ButterKnife.inject(this, view);
    }
}

3.8. Intent数据显示在标题上

//初始化页面的控件并缓存在ViewHolder里面
View view = View.inflate(this, R.layout.activity_bussiness,null);
mHd = newBusinessViewHolder(view);
setContentView(view);
//从intent里面获取条目数据
Intent intent = getIntent();
HomeData.BodyInfo item = (HomeData.BodyInfo) intent.getSerializableExtra("item");
//设置标题
mHd.tvTitle.setText(item.seller.name);
//添加返回关闭
mHd.ibBack.setOnClickListener(newView.OnClickListener() {
    @Override
    public voidonClick(View v) {
        finish();
    }
});

 

3.9. 初始化TabLayoutViewPager

运行效果

 

>1.初始化

Veiwpager设置一个适配器

TabLayout设置一个viewPager

如果TabLayout不显示标题重写getPageTitle方法

//初始化tab
String[] names =new String[]{"商品","评价","商家"};
for (String name : names) {
    TabLayout.Tab tab =mHd.tabLayout.newTab().setText(name);
    mHd.tabLayout.addTab(tab);
}
//初始化ViewPager,包含三个标题对应的三个Fragment页面
BusinessActivityVpAdapter adapter =new BusinessActivityVpAdapter(getSupportFragmentManager());
mHd.viewpager.setAdapter(adapter);
//绑定指示器与ViewPager,让用户点击标题切换viewpager,切换viewpager可以同步标题
mHd.tabLayout.setupWithViewPager(mHd.viewpager);

>2.创建适配器

com.itheima.app_.ui.adapter.BusinessActivityVpAdapter

public classBusinessActivityVpAdapterextends FragmentPagerAdapter {
    //页面集合 装载Fragment页面
    
privateList<Fragment>mPages = newArrayList<>();
    privateString[]mNames = newString[]{"商品","评价","商家"};
    publicBusinessActivityVpAdapter(FragmentManager fm) {
        super(fm);
        mPages.add(newGoodFragment());
        mPages.add(newCommentFragment());
        mPages.add(newBusinessFragment());
    }
    //一定要重写,否则指示器获取不到标题
    
@Override
    publicCharSequence getPageTitle(intposition) {
        returnmNames[position];
    }
    //返回页面
    
@Override
    publicFragment getItem(intposition) {
        returnmPages.get(position);
    }
    //表示 vp的页面数
    
@Override
    public intgetCount() {
        returnmPages.size();
    }
}

以上使用到的Fragment页面与布局

    

>4.控件购物车显示逻辑

购物车只在ViewPager的下标为0时才显示,其它下标均隐藏

  //添加页面切换事件处理
    
mHd.viewpager.addOnPageChangeListener(listener);

private ViewPager.OnPageChangeListenerlistener = newViewPager.OnPageChangeListener() {
    @Override
    public voidonPageSelected(intposition) {
        //页号为0显示底部购物车 其它隐藏
        
mHd.bottom.setVisibility(position==0?View.VISIBLE:View.GONE);//使用表达式可以简化代码
    }
    @Override
    public voidonPageScrolled(intposition,float positionOffset,int positionOffsetPixels) {
    }
    @Override
    public voidonPageScrollStateChanged(intstate) {
    }
};
@Override
protected voidonDestroy() {
    super.onDestroy();
    mHd.viewpager.removeOnPageChangeListener(listener);
}

 

 

 

4. 获取商铺页面的商品信息

运行效果

 

4.1. UI布局分析

左侧是可以一个固定宽度,右侧使用权重。

两侧可以都是权重 1:3

 

4.2. 编写GoodFragmentPresenter获取服务端数据

运行效果

 

 

>1.增加retrofit接口方法

com.itheima.app_.model.net.TakeOutApi

@GET(Contants.BUSINESS)
Call<ResponseData> getBusiness(@Query("sellerId")String sellerId);

>2.编写GoodFragmentPresenter核心逻辑

com.itheima.app_.presenter.GoodFragmentPresenter

//mvp 中的p是获取数据,处理线程的核心对象
public classGoodFragmentPresenterextends BasePresenter {
    //View
    
privateGoodFragmentmView;
    publicGoodFragmentPresenter() {
    }
    public voidsetView(GoodFragment view) {
        this.mView= view;
    }
    public voidreset() {
        this.mView= null;
    }
    //Module
    
privateBusinessDatadata;
    public voidgetData(){
        //调用v显示等待
        
this.mView.showLoading();
        Call<ResponseData> call = HttpUtils2.getApi().getBusiness(BussinessActivity.sSellerId);
        SimpleCallBack callBack=newSimpleCallBack(){
            @Override
            protected voidshowError(inti, RuntimeException e) {
                super.showError(i, e);
                //调用v显示出错提示
                
System.out.println(e.getMessage());
                mView.showError(e.getMessage());
            }
            @Override
            protected voidshowData(String json) {
                super.showData(json);
                //把json数据解析后显示在界面
                
BusinessData data=  newGson().fromJson(json,BusinessData.class);
                mView.showData(data);
            }
        };
        call.enqueue(callBack);
    }
}

 

可以在debug模式下获取json数据进行解析,解析的javaBean不用自己编写,使用gsonFromat自动生成

 


4.3. 使用dagger2管理GoodFragmentPresenter

>1.使用@module@provides创建工厂

@Module
public classHomeFragmentModule {
    @Provides
    publicHomeFragmentPresenter providerPresneter() {
        return newHomeFragmentPresenter();
    }
}

>2.使用@component创建注入器

@Component(modules = {HomeFragmentModule.class})
public interfaceHomeFragmentComponent {
    public voidinject(HomeFragment fragment);
}

>3.GoodFragment使用@Inject注入presenter实例,注意实例不能为private,同时要点run按钮

@Inject
public GoodFragmentPresenterpresenter;

@Override
public voidonViewCreated(View view,@Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    //获取当页面的id向服务端发送请求
    //presenter = new GoodFragmentPresenter();
    
DaggerGoodFragmentComponent.builder().
            goodFragmentModule(newGoodFragmentModule())
            .build()
            .inject(this);
    presenter.setView(this);
    presenter.getData();
}

 

4.4. 有了数据以后,即可编写数据显示

com.itheima.app_.ui.fragment.GoodFragment

>1.初始化recyclerView

public voidshowLoading() {
    Toast.makeText(getContext(),"正在加载...", Toast.LENGTH_SHORT).show();
}
public voidshowError(String message) {
   Toast.makeText(getContext(),"加载数据失败.", Toast.LENGTH_SHORT).show();
}
public voidshowData(BusinessData data) {
    //列表的排列效果
    
goodTypes.setLayoutManager(newLinearLayoutManager(getContext()));
    GoodTypeAdapter adapter=newGoodTypeAdapter(data.list);
    goodTypes.addItemDecoration(newRecycleViewDivider(getContext(),LinearLayoutManager.VERTICAL));
    goodTypes.setAdapter(adapter);
}

>2.recyclerView的显示关键在适配器。

1)编写holderitem视图

layout/item_type.xml

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:clickable="true"
    android:layout_height="wrap_content"
    android:minHeight="80dp"
    android:background="#b9dedcdc"
    android:orientation="vertical"
>
    <TextViewandroid:gravity="center"
        android:id="@+id/tv_count"
        android:layout_marginTop="5dp"
        android:textColor="#fff"
        android:text="1"
        android:visibility="invisible"
        android:layout_marginRight="5dp"
        android:textSize="12sp"
        android:background="@drawable/circle_red"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
      
/>
    <TextView
        android:layout_width="match_parent"
        android:gravity="center"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:padding="5dp"
        android:id="@+id/type"
        android:text="种类1"
>
    </TextView>
</RelativeLayout>

com.itheima.app_.ui.holder.GoodTypeHolder(holder代码不用自己写,可以通过butterknife生成)

public classGoodTypeHolderextends RecyclerView.ViewHolder {
    @InjectView(R.id.tv_count)
    public  TextView tvCount;
    @InjectView(R.id.type)
    publicTextView type;
    publicGoodTypeHolder(View itemView) {
        super(itemView);
        intlayoutId = R.layout.item_type;
        ButterKnife.inject(this,itemView);
    }
}

>3.有了hd就可以快速编写Adapter

com.itheima.app_.ui.adapter.GoodTypeAdapter

public classGoodTypeAdapterextends RecyclerView.Adapter<GoodTypeHolder> {
    publicList<BusinessData.GoodType>mData;
    publicGoodTypeAdapter(List<BusinessData.GoodType> list) {
        mData=list;
    }
    //给rv创建条目的缓存holder
    
@Override
    publicGoodTypeHolder onCreateViewHolder(ViewGroup parent,int viewType) {
      //  View view= View.inflate(parent.getContext(), R.layout.item_type,null);
        
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item_type,parent,false);
        GoodTypeHolder hd=newGoodTypeHolder(view);
        returnhd;
    }
    privateInteger mSelectedPosition=0;//记录当前选中位置
//给每个条目赋值
@Override
public voidonBindViewHolder(GoodCategoryHolder holder,final int position) {
    finalBusinessData.GoodType type =mData.get(position);
    holder.type.setText(type.name);
    //调整背景颜色
    
holder.itemView.setBackgroundColor(position==mSelectedPosition? Color.WHITE:Color.parseColor("#b9dedcdc"));
    holder.itemView.setOnClickListener(newView.OnClickListener() {
        @Override
        public voidonClick(View v) {
            //选中的使用白色背景 未选中的灰色
            
mSelectedPosition=position;
            //刷新
            
notifyDataSetChanged();
                   }
    });
}

    //给rv提供数据
    
@Override
    public intgetItemCount() {
        returnmData.size();
    }
}

>4.编写类别选中

同上方红色代码

4.5. 完成左侧类别,即可显示右侧分组列表

 


>1.在获取数据后将数据按照headId进行排列

@Override
protected voidshowData(String json) {
    super.showData(json);
    //把json数据解析后显示在界面
    
BusinessData data =new Gson().fromJson(json, BusinessData.class);
    mGoodDatas= new ArrayList<>();
    //遍历商品类别
    
List<BusinessData.GoodType> list = data.list;
    for(intheadId =0; headId < list.size(); headId++) {
        //从类别中取出每个商品信息
        
BusinessData.GoodType type = list.get(headId);
        //保存组名
        
String groupName = type.name;
        List<BusinessData.GoodType.GoodInfo> goodList = type.list;
        //将商品信息再进行分组,就得给每个商品设置headId
        
for(BusinessData.GoodType.GoodInfo info : goodList) {
            GoodData eachGood =new GoodData(headId, groupName, info);
            //添加进集合
            
mGoodDatas.add(eachGood);
        }
    }
    mView.showData(list,mGoodDatas);

}

>2.用到的GoodData对象包含headId

com.itheima.app_.model.bean.GoodData

public classGoodData {
    public intheadId;
    publicString typeName;
    publicBusinessData.GoodType.GoodInfoinfo;
    publicGoodData(intheadId, String typeName, BusinessData.GoodType.GoodInfo info) {
        this.headId= headId;
        this.typeName= typeName;
        this.info= info;
    }
}

>3.编写显示逻辑

com.itheima.app_.ui.fragment.GoodFragment#showData

public voidshowData(List<BusinessData.GoodType> list, List<GoodData> goodDatas) {
    //列表的排列效果
    
goodTypes.setLayoutManager(newLinearLayoutManager(getContext()));
    finalGoodCategoryAdapter adapter =new GoodCategoryAdapter(list);
    goodTypes.addItemDecoration(newRecycleViewDivider(getContext(), LinearLayoutManager.VERTICAL));
    goodTypes.setAdapter(adapter);
    //分组列表
    
finalGoodStickListAdapter goodStickListAdapter =new GoodStickListAdapter(goodDatas);
    goodList.setAdapter(goodStickListAdapter);
    AbsListView.OnScrollListener scollListener =new AbsListView.OnScrollListener() {
        @Override
        public voidonScrollStateChanged(AbsListView view,int scrollState) {
        }
        @Override
        public voidonScroll(AbsListView view,int firstVisibleItem,int visibleItemCount,int totalItemCount) {
            //获取当前显示列表显示第一项对应的position; 拿这个position跟左侧选中的类别的headId比较
            
GoodData item = goodStickListAdapter.getItem(firstVisibleItem);
            if(item.headId!= adapter.getSelectedPosition()) {
                adapter.setSelectedPosition(item.headId);
            }
        }
    };
    goodList.setOnScrollListener(scollListener);
}

>4.滑动商品列表,切换商品类别

同上方红色字体代码 OnScrollListener 基本逻辑是拿出商品列表的顶部的元素查询headId.将左侧的商品类别

数据调到选中位置

>5.选中左侧商品类别

com.itheima.app_.ui.adapter.GoodCategoryAdapter#getSelectedPosition

//获取选中组
publicInteger getSelectedPosition() {
    returnmSelectedPosition;
}
//修改选中组
public voidsetSelectedPosition(intposition) {
    mSelectedPosition=position;
    notifyDataSetChanged();
}
private Integer mSelectedPosition=0;//记录当前选中位置

>6.点击左侧商品类别切换右侧商品列表(引入eventBus3.0

com.itheima.app_.ui.adapter.GoodCategoryAdapter#onBindViewHolder

holder.itemView.setOnClickListener(newView.OnClickListener() {
    @Override
    public voidonClick(View v) {
        //选中的使用白色背景 未选中的灰色
        
mSelectedPosition=position;
        //刷新
        
notifyDataSetChanged();
        EventBus.getDefault().post(mSelectedPosition);//发送id给GoodFragment要求商品列表
        //滚动到该类别下的第一个元素 比如id为101,那个显示13.9特价套餐的第一个商品
    
}
});

这里为什么要引入eventbus3.0

因为在这里写点击事件要求GoodFragment切换rv.

这样要用到presenterrv,不如把选中下标以消息的方式发送出去,在GoodFragment

页面接收参数切换选中位置,可以不受参数限制。

具体用法:

1)依赖eventBus

//使用eventbus3.0方便参数传递
compile 'org.greenrobot:eventbus:3.0.0'

2)GoodFragment页面注册与处理

EventBus.getDefault().register(this);

//接收点击的商品类型的id
@Subscribe(threadMode = ThreadMode.MAIN)
public voidonEvent(Integer groupId) {
    //选择 typeId组的第一个元素
    
intpostion=presenter.findPositionForGroupFirst(groupId);
    goodList.setSelection(postion);
}

3)GoodFragment销毁后移除

EventBus.getDefault().unregister(this);

5. 购物车页面

5.1. 购物车特效-贝塞尔曲线

 

购物车特效原理:

1.从添加按钮获取开始坐标

2.从购物车图标获取结束坐标

3.打气一个视图,添加属性动画ObjectAnimator(缩小),ValueAnimator(路线)

4.动画开始时添加该视图,动画结束删除该视图

5.运动路径使用TypeEvaluator与贝塞尔函数计算

 

>1.创建布局UI

layout/activity_main.xml

<?xml version="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rl"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.c.com.beziercurveanimater.MainActivity"
>
    <cn.c.com.beziercurveanimater.ex.MyCartAnimView
        android:id="@+id/move"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
/>
    <Button
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentRight="true"
        android:onClick="buy"
        android:text="+"
/>

    <ImageView
        android:id="@+id/cart"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:src="@drawable/gouwuche"
/>
</RelativeLayout>

 

移动控件(项目中不是把条目上的+按钮进行移动,而是添加一个新view进行移动)

<?xml version="1.0"encoding="utf-8"?>
<ImageViewxmlns:android="http://schemas.android.com/apk/res/android"
           android:layout_width="50dp"
           android:layout_height="50dp"
           android:orientation="vertical"
           android:src="@drawable/coin1"
    
/>

>2.初始化事件

cn.c.com.beziercurveanimater.MainActivity

public classMainActivityextends AppCompatActivity {
    privateImageViewcart;
    privateMyCartAnimViewanimview;
    @Override
    protected voidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        cart= (ImageView) findViewById(R.id.cart);
        animview= (MyCartAnimView) findViewById(R.id.move);
    }
    public voidbuy(View view) {
        animview.startAnim(view,cart, R.layout.cart_anim);
    }
}

>3.自定义控件CartAnimView

public classMyCartAnimViewextends FrameLayout {
    publicMyCartAnimView(Context context) {
        this(context,null,0);
    }
    publicMyCartAnimView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }
    publicMyCartAnimView(Context context, AttributeSet attrs,int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    //主要是三个元素 一个ImageView按照点击 的按钮位置 以抛物线的方式 滑动到 购物车控件位置
    //1.重写onLayout方法 初始化当前布局的坐标
    
privatePointF mLocation = newPointF();//坐标对象包含x,y
    
@Override
    protected voidonLayout(booleanchanged,int left, inttop, int right,int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        int[] l =new int[2];
        getLocationInWindow(l);
        mLocation.set(l[0], l[1]);//初始化布局位置
    
}
    //2.编写开始动画方法
    //3.保存移动控件的坐标
    
public voidstartAnim(finalView startView,final View endView, final int moveLayoutId) {
        //使用属性动画创建 移动与缩放效果
        
AnimatorSet set =new AnimatorSet();
        //路径动画怎么处理?1.确定开始位置 2.结束位置 3.中间运行坐标使用贝塞尔曲线计算
        //1.开始位置
        
PointF startF=newPointF();
        int[] startLoc=new int[2];
        startView.getLocationInWindow(startLoc);
        startF.set(startLoc[0]-mLocation.x,startLoc[1]-mLocation.y);
        //2.结束位置
        
PointF endF=newPointF();
        if(endView ==null) {
           //使用左下角默认作为购物车控件位置
            
endF.set(0,getMeasuredHeight());
        }else
        
{//计算购物车坐标
            
int[] mEndLoc=new int[2];
            endView.getLocationInWindow(mEndLoc);
            //相对布局坐标
            
endF.set(mEndLoc[0]-mLocation.x,mEndLoc[1]-mLocation.y);
        }
        //3.移动控件
         
final  View moveView= LayoutInflater.from(getContext()).inflate(moveLayoutId,this,false);
        //创建坐标变化函数
        
TypeEvaluator evaluator=newMyBezierEvaluator();
        ValueAnimator pathAnim = ObjectAnimator.ofObject(evaluator,startF,endF);
        pathAnim.addUpdateListener(newValueAnimator.AnimatorUpdateListener() {
            @Override
            public voidonAnimationUpdate(ValueAnimator animation) {
                PointF newF= (PointF) animation.getAnimatedValue();
                //更新给坐标
                
moveView.setX(newF.x);
                moveView.setY(newF.y);
            }
        });
        set.playTogether(
                ObjectAnimator.ofFloat(moveView,"scaleX",1.0f,0.3f),//缩小
                
ObjectAnimator.ofFloat(moveView,"scaleY",1.0f,0.3f),//缩小
                
pathAnim
        );
        // 现在这个moveView还不属于当前布局内的元素,所以不能显示在当前布局,可以在特效开始前添加
        //特效结束后删除
        
set.addListener(newAnimator.AnimatorListener() {
            @Override
            public voidonAnimationStart(Animator animation) {
                MyCartAnimView.this.addView(moveView);//动画开始添加
            
}
            @Override
            public voidonAnimationEnd(Animator animation) {
                MyCartAnimView.this.removeView(moveView);//动画结束 删除
            
}
            @Override
            public voidonAnimationCancel(Animator animation) {
            }
            @Override
            public voidonAnimationRepeat(Animator animation) {
            }
        });
        set.setDuration(1000);
        set.start();
    }
    //创建曲线函数
    
private classMyBezierEvaluatorimplements TypeEvaluator<PointF> {
        @Override
        publicPointF evaluate(floatfraction, PointF startValue, PointF endValue) {
            System.out.println("fraction="+fraction);
            //返回变化的轨迹坐标
            
PointF newF=newPointF((startValue.x+endValue.x)/2,0);
            returnBezierCurve.bezier(fraction,startValue,newF ,endValue);
        }
    }
}

 

 

 

5.2. 创建购物车对象Cart

一进页面显示获取项目的单例购物车对象,取出针对卖家添加的商品内容

,包括数量,价格,配送费,起送价(总价超过起送价显示结算)


 

所以要深刻里面 商品购物项与 购物车之间的包含关系

 

 

>1.com.itheima.app_.model.bean.CartItem 购物项

public classCartItem {
    privateString sellerId;//商铺id
    
private inttypeId;//类别id
    
private intgoodsId;//商品id
    
private intcount;//商品数量
    
private floatpriceSingle;//单品价格
    
privateString goodName;//商品名称

//省略get set

}

>2.com.itheima.app_.model.bean.Cart 购物

public classCart {
    public static final intADD =1;
    public static final intMINU = -1;
    private staticCart sCart;
    privateCart() {
    }
    public staticCart getCart() {
        if(sCart== null) {
            sCart= newCart();
        }
        returnsCart;
    }
    //一个购物车包含多个购物项,是集合与元素的关系
    
privateList<CartItem>mList = newArrayList<>();

为什么是单例?

一个app只有一个购物车,多个购物车实例会引起结算问题,试想你推送一辆购物车去收银台结算容易,还是100辆容易?

>3.支持条目的上增加与减少按钮的数据处理

//添加元素
public voidadd(String sellerId,  inttypeId,intgoodsId,String goodName,floatpriceSingle) {
    CartItem result = findItemByGoodId(goodsId);
    if(result ==null) {
        CartItem cartItem =new CartItem( sellerId,  typeId,  goodsId, goodName,priceSingle);
        mList.add(cartItem);
    }
}
//更新元素
public voidupdate(intgoodsId,int operate) {
    CartItem result = findItemByGoodId(goodsId);
    if(result !=null) {
        if(operate ==ADD) {
            result.setCount(result.getCount() +1);
        } else {
            result.setCount(result.getCount() -1);
            if(result.getCount() ==0) {
                mList.remove(result);
            }
        }
    }
}
//查找元素
publicCartItem findItemByGoodId(intgoodId) {
    for(CartItem item :mList) {
        if(item.getGoodsId() == goodId) {
            returnitem;
        }
    }
 return null;
}
//查看指定的卖家sellerId在购物车里面的数量 决定 是否要显示-号与数量
public intfindCountBySellerId(String sellerId) {
    intcountSelect =0;
    for(CartItem item :mList) {
        if(TextUtils.equals(sellerId, item.getSellerId())) {
            countSelect += item.getCount();
        }
    }
    returncountSelect;
}
//获取指定商家的总价
public floatfindPriceCountBySellerId(String sellerId) {
    floatcountPrice =0;
    for(CartItem item :mList) {
        if(TextUtils.equals(sellerId, item.getSellerId())) {
            countPrice += (item.getCount()*item.getPriceSingle());
        }
    }
    returncountPrice;
}

建议使用Android4Junit进行测试,以确保购物车没有bug,后面就可以由条目调用

 

5.3. 点击+号添加-号减少

 

com.itheima.app_.ui.adapter.GoodStickListAdapter#getView

 

  hd.tvName.setText(info.name);//商品名
    
hd.tvContain.setText(info.form);//组成
    
hd.tvSaleCount.setText("月销售出"+ info.monthSaleNum);//月销售
    
hd.tvNewprice.setText("$"+ info.newPrice);//新价格
    
hd.tvOldprice.setText("$"+ info.oldPrice);//旧价格
    
hd.tvOldprice.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);//删除实线
    //加载图片
    
Picasso.with(convertView.getContext()).load(info.icon).into(hd.ivIcon);
    finalGoodItemViewHolder currHd = hd;
    //添加商品
    
hd.ibAdd.setOnClickListener(newView.OnClickListener() {
        @Override
        public voidonClick(View v) {
            //添加进购物车
            
GoodData goodData =mData.get(position);
            CartItem item = Cart.getCart().findItemByGoodId(info.id);
            if(item ==null) {
                Cart.getCart().add(BussinessActivity.sSellerId, goodData.headId, goodData.info.id,info.name,info.newPrice);
            } else {
                Cart.getCart().update(goodData.info.id, Cart.ADD);
            }
            //刷新
           
notifyDataSetChanged();
            Message msg =new Message();
            msg.what= Cart.ADD;
            msg.obj= v;
            EventBus.getDefault().post(msg);
        }
    });
    //删除操作
    
hd.ibMinus.setOnClickListener(newView.OnClickListener() {
        @Override
        public voidonClick(View v) {
            GoodData goodData =mData.get(position);
            Cart.getCart().update(goodData.info.id, Cart.MINU);
            //刷新
            
notifyDataSetChanged();
            Message msg =new Message();
            msg.what= Cart.MINU;
            msg.obj= null;//删除不需要抛物线动画
            
EventBus.getDefault().post(msg);
        }
    });
    //刷新列表 上的-号状态与数量
    
updateCountMinuState(hd, info);
    returnconvertView;
}
private voidupdateCountMinuState(GoodItemViewHolder hd, BusinessData.GoodType.GoodInfo info) {
    CartItem item = Cart.getCart().findItemByGoodId(info.id);
    if(item ==null || item.getCount() ==0) {
        hd.ibMinus.setVisibility(View.INVISIBLE);
        hd.tvCount.setVisibility(View.INVISIBLE);
        hd.tvCount.setText("0");
    } else{
        hd.ibMinus.setVisibility(View.VISIBLE);
        hd.tvCount.setVisibility(View.VISIBLE);
        hd.tvCount.setText(item.getCount() +"");
    }
}

 

5.4. +-操作没问题后,再提交界面要求更新底部购物车状态


     

>1.一个页面要接收eventbus传递的参数

EventBus.getDefault().register(this);

EventBus.getDefault().unregister(this);

>2.添加接收方法接收参数,注意方法建议以onEvent命名

@Subscribe(threadMode = ThreadMode.MAIN)
public voidonEvent(Message msg) {
    if(msg.what== Cart.ADD) {
        //购物车添加 显示特效
        
if(cartAnimView== null) {
            cartAnimView= (MyCartAnimView) findViewById(R.id.cart_anim);
        }
        cartAnimView.startAnim((View) msg.obj,mHd.imgCart, R.layout.view_move);
    } else if(msg.what== Cart.MINU) {
        //删除
    
}
    updateCartUI();
}
@Override
protected voidonResume() {
    super.onResume();
    updateCartUI();
}
//查询购物车显示购物车状态
private voidupdateCartUI() {
    //更新购买数量
    
intcount = Cart.getCart().findCountBySellerId(sSellerId);
    mHd.tvSelectNum.setText(count + "");
    mHd.tvSelectNum.setVisibility(count > 0 ? View.VISIBLE: View.INVISIBLE);
    //更新总价
    
floattotalPrice = Cart.getCart().findPriceCountBySellerId(sSellerId);
    mHd.tvCountPrice.setText(""+ CountPriceFormater.format(totalPrice));
    mHd.tvSendPrice.setText("$"+ 30 +"起送");
    mHd.tvDeliveryFee.setText("另需配置送费$"+ 5);
    //如果总价大于配置总
    
mHd.tvSubmit.setVisibility(totalPrice > 30f ? View.VISIBLE: View.GONE);
    mHd.tvSendPrice.setVisibility(totalPrice > 30f ? View.GONE: View.VISIBLE);
}

>3.如果没有问题就添加购物车特效

layout/activity_bussiness.xml

<com.itheima.app_.ui.MyCartAnimView
    android:id="@+id/cart_anim"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="60dp"
/>

调用如上红色代码

 

5.5. 添加购物车弹出视图编写显示逻辑

 

>1.布局UI

layout/cart_list.xml

<?xml version="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"android:layout_width="match_parent"
    android:layout_height="wrap_content"
>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#d7d4d4"
>
        <ImageView
            android:id="@+id/iv"
            android:layout_width="5dp"
            android:layout_height="20dp"
            android:background="#227be1"
            android:layout_centerVertical="true"
            android:layout_marginLeft="20dp"
/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="15dp"
            android:layout_toRightOf="@+id/iv"
            android:text="购物车"
/>
        <TextView
            android:id="@+id/tvClear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="15dp"
            android:gravity="left|center_vertical"
            android:drawableLeft="@drawable/icon_clean_up"
            android:layout_alignParentRight="true"
            android:drawablePadding="5dp"
            android:layout_marginRight="20dp"
            android:text="清空"
/>
    </RelativeLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_cart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
/>

</LinearLayout>

layout/item_cart.xml

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:background="#FFFFFF"
    android:gravity="center_vertical"
>
    <TextView
        android:id="@+id/tv_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="5dp"
        android:layout_weight="1"
        android:maxLines="1"
        android:text="--商品"
        android:textColor="#000"
        android:textSize="12sp"
/>
    <TextView
        android:id="@+id/tv_type_all_price"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="10dp"
        android:text="¥0"
        android:textColor="#cd5656"
        android:textSize="20sp"
/>
    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:orientation="horizontal"
>
        <ImageButton
            android:id="@+id/ib_minus"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:background="@drawable/button_minus"
            android:visibility="visible"
/>
        <TextView
            android:id="@+id/tv_count"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:text="0"
            android:textColor="#000"
            android:textSize="15sp"
            android:visibility="visible"
/>
        <ImageButton
            android:id="@+id/ib_add"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_marginRight="20dp"
            android:background="@drawable/button_add"
/>
    </LinearLayout>
</LinearLayout>

>2.创建菜单控件的缓存holder(holder是使用集合的方式管理界面控件)

com.itheima.app_.ui.activity.BussinessActivity.CardListViewHolder

static classCardListViewHolder {
    View sheetView;
    @InjectView(R.id.iv)
    ImageView iv;
    @InjectView(R.id.tvClear)
    TextView tvClear;
    @InjectView(R.id.rv_cart)
    RecyclerView rvCart;

    publicCardListViewHolder(Context context) {
        intlayoutId = R.layout.cart_list;
        this.sheetView=View.inflate(context, layoutId,null);
        ButterKnife.inject(this,sheetView);
    }
    public voidshowCartList()
    {

        //列表显示
        
rvCart.setLayoutManager(newLinearLayoutManager(rvCart.getContext()));
        //添加适配器
        
CartItemAdapter adapter=newCartItemAdapter();
        rvCart.setAdapter(adapter);
    }
}

com.itheima.app_.ui.activity.BussinessActivity.BusinessViewHolder#onClick

@OnClick(R.id.bottom)
public voidonClick() {
    //关联底部购物车列表
    //如果购物车列表是显示的则隐藏
    
if(bottomSheetLayout!=null)
    {
        if(bottomSheetLayout.isSheetShowing()) {
            bottomSheetLayout.dismissSheet();//隐藏
        
}else {
            this.cartSheetHd.showCartList();
            bottomSheetLayout.showWithSheetView(cartSheetHd.sheetView);//显示
        
}
    }

}

>3.碰到rv关键就是适配器的创建(holder+adapter

com.itheima.app_.ui.holder.CartItemViewHolder (代码都自动生成的)

com.itheima.app_.ui.adapter.CartItemAdapter

@Override
public voidonBindViewHolder(CartItemViewHolder holder,int position) {
   final  CartItem cartItem =mData.get(position);
    holder.tvName.setText(cartItem.getGoodName());//显示价格
    
holder.tvCount.setText(cartItem.getCount()+"");//显示数量
    
floatprice=cartItem.getPriceSingle()*cartItem.getCount();//显示总价
    
holder.tvTypeAllPrice.setText(CountPriceFormater.format(price));
    //添加点击事件
    
holder.ibAdd.setOnClickListener(newView.OnClickListener() {
        @Override
        public voidonClick(View v) {
            Cart.getCart().update(cartItem.getGoodsId(),Cart.ADD);
            mData=Cart.getCart().findCartItemsBySellerId(BussinessActivity.sSellerId);
            notifyDataSetChanged();
            //更新
            
Message msg=newMessage();
            msg.what= Contants.CART_ITEM_ADD;
            EventBus.getDefault().post(msg);
        }
    });
    holder.ibMinus.setOnClickListener(newView.OnClickListener() {
        @Override
        public voidonClick(View v) {
            Cart.getCart().update(cartItem.getGoodsId(),Cart.MINU);
            mData=Cart.getCart().findCartItemsBySellerId(BussinessActivity.sSellerId);
            notifyDataSetChanged();
            Message msg=newMessage();
            msg.what= Contants.CART_ITEM_MIN;
            EventBus.getDefault().post(msg);
        }
    });

}

通知列表刷新即adapter.notifyDatasetChanged(还有要刷新的有底部列表与右侧商品列表)

要点:找到适配器进行刷新调用。

com.itheima.app_.ui.activity.BussinessActivity

@Subscribe(threadMode = ThreadMode.MAIN)
public voidonEvent(Message msg) {
    if(msg.what== Cart.ADD) {
        //购物车添加 显示特效
        
if(cartAnimView== null) {
            cartAnimView= (MyCartAnimView) findViewById(R.id.cart_anim);
        }
        cartAnimView.startAnim((View) msg.obj,mHd.imgCart, R.layout.view_move);
        updateCartUI();
    } else if(msg.what== Cart.MINU) {
        //删除
        
updateCartUI();
    }else if(  msg.what == Contants.CART_ITEM_ADD) {
        updateCartUI();
    }else if(  msg.what== Contants.CART_ITEM_MIN) {
        updateCartUI();
    }
}

com.itheima.app_.ui.fragment.GoodFragment

@Subscribe(threadMode = ThreadMode.MAIN)
public voidonEvent(Message msg) {
    //选择 typeId组的第一个元素
    
if(msg.what== Contants.CART_ITEM_ADD|| msg.what== Contants.CART_ITEM_MIN) {
        mGoodStickListAdapter.notifyDataSetChanged();
    }
}

引处可见eventBus的灵活性

5.6. 清空购物车逻辑


清空的思路

清空购物车里面所有的购物项CartItem

刷新当前购物车

刷新底部购物车状态

刷新右侧商品列表

只要一个消息即可,这也是eventBus的简洁

com.itheima.app_.ui.activity.BussinessActivity.CardListViewHolder

public voidshowCartList()
{
    //列表显示
    
rvCart.setLayoutManager(newLinearLayoutManager(rvCart.getContext()));
    //添加适配器
    
CartItemAdapter adapter=newCartItemAdapter();
    rvCart.setAdapter(adapter);
    tvClear.setOnClickListener(newView.OnClickListener() {
        @Override
        public voidonClick(View v) {
            //清空弹出对话框提示
            
showDialog(v.getContext());
        }

    });
}

private voidshowDialog(Context context) {
    newAlertDialog.Builder(context).setTitle("清空购物车")
            .setPositiveButton("确认",new DialogInterface.OnClickListener() {
                @Override
                public voidonClick(DialogInterface dialog,int which) {
                    Cart.getCart().clearAll();
                    showCartList();//重新显示列表
                    
Message msg=newMessage();
                    msg.what=Contants.CART_ITEM_ADD;
                    EventBus.getDefault().post(msg);
                }
            })//
            
.setNegativeButton("取消",null)//
            
.create()//
            
.show();;
}

 

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值