最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android仿外賣購物車功能

 更新時間:2021年04月22日 15:49:52   作者:ASleepyCoder  
這篇文章主要為大家詳細介紹了Android仿外賣購物車功能的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了Android實現(xiàn)外賣購物車功能的具體代碼,供大家參考,具體內(nèi)容如下

先看看效果圖:

知識點分析

效果圖來看不復雜內(nèi)容并沒多少,值得介紹一下的知識點也就下面幾個吧
- 列表標題懸停
- 左右列表滑動時聯(lián)動
- 添加商品時的拋物線動畫
- 底部彈出購物車清單
- 數(shù)據(jù)的同步

另外就是實現(xiàn)效果的時候可能會遇到的幾個坑。。。

布局很簡單直接進入代碼

1:列表標題懸停

現(xiàn)在做項目列表什么的基本拋棄了ListView改用RecyclerView,上篇博客中的標題懸停也是使用了一個RecyclerView的開源項目sticky-headers-recyclerview,不過寫這個demo的時候遇到了兩個坑

1)、sticky-headers-recyclerview做懸停標題的時候scrollToPosition(int position)方法滾動的位置不準確。
2)、當布局復雜點的時候 如果RecyclerView的寬度自適應或者使用權重百分比之類可能會導致header顯示空白。

并且該開源項目作者已經(jīng)停止維護,所以這次又換回了StickyListHeadersListView。

需要購物車Demo的很多都是新手,這里簡單介紹下StickyListHeadersListView的使用

1)、AS引用 gradle文件dependencies內(nèi)添加

compile 'se.emilsjolander:stickylistheaders:2.7.0'

2)、xml文件中使用StickyListHeadersListView代替ListView

 <se.emilsjolander.stickylistheaders.StickyListHeadersListView
  android:layout_width="match_parent"
  android:background="#fff"
  android:id="@+id/itemListView"
  android:layout_height="match_parent">
 </se.emilsjolander.stickylistheaders.StickyListHeadersListView>

3)、Adapter繼承BaseAdapter和接口StickyListHeadersAdapter
StickyListHeadersAdapter接口包括兩個方法

View getHeaderView(int position, View convertView, ViewGroup parent);

long getHeaderId(int position);

代碼中使用和ListView一樣,下面是幾個特有的方法,看方法名也很容易理解用途

public void setAreHeadersSticky(boolean areHeadersSticky);
public boolean areHeadersSticky();

public void setOnHeaderClickListener(OnHeaderClickListener listener);

public interface OnHeaderClickListener {
 public void onHeaderClick(StickyListHeadersListView l, View header, int itemPosition, long headerId, boolean currentlySticky);
}

public void setOnStickyHeaderChangedListener(OnStickyHeaderChangedListener listener);

public interface OnStickyHeaderChangedListener {
 void onStickyHeaderChanged(StickyListHeadersListView l, View header, int itemPosition, long headerId);
}

public View getListChildAt(int index);
public int getListChildCount();

2:左右列表聯(lián)動

聯(lián)動主要有兩個效果
- 左側列表點擊選擇分類,右側列表滑動到對應分類
- 右側列表滑動過程中左側列表高亮的分類跟隨變化

第一個效果簡單,左側列表item添加點擊事件,事件中調(diào)用右側列表的setSelection(int positon) 方法。

第二個效果要給右側列表添加ScrollListener,根據(jù)列表中顯示的第一條數(shù)據(jù)設置左側選中的分類

 listView.setOnScrollListener(new AbsListView.OnScrollListener() {
   @Override
   public void onScrollStateChanged(AbsListView view, int scrollState) {

   }

   @Override
   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
   //根據(jù)firstVisibleItem獲取分類ID,根據(jù)分類id獲取左側要選中的位置
    GoodsItem item = dataList.get(firstVisibleItem);
    if(typeAdapter.selectTypeId != item.typeId) {
     typeAdapter.selectTypeId = item.typeId;
     typeAdapter.notifyDataSetChanged();
     //左側列表是個RecyclerView 所以使用smoothScrollToPosition(int position) 使當對應position的item可以滾動顯示出來
     rvType.smoothScrollToPosition(int position)(getSelectedGroupPosition(item.typeId));
    }
   }
  });

3:添加商品的動畫

添加商品一共有三個動畫
- 當商品從0到1 旋轉(zhuǎn)左移顯示出減號按鈕
- 當商品從1到0 減號按鈕旋轉(zhuǎn)右移消失
- 添加商品時拋物線動畫添加到購物車圖標

前兩個動畫很簡單可以分解成三個補間動畫 旋轉(zhuǎn)、平移、透明度。
可以用xml完成,也可以代碼設置,不過有個小坑要注意一下 旋轉(zhuǎn)動畫一定要在平移動畫前面,否則就不是滾動平移了,而是亂跳。。。

這里貼一下動畫的代碼設置方法

 //顯示減號的動畫
 private Animation getShowAnimation(){
  AnimationSet set = new AnimationSet(true);
  RotateAnimation rotate = new RotateAnimation(0,720,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);
  set.addAnimation(rotate);
  TranslateAnimation translate = new TranslateAnimation(
    TranslateAnimation.RELATIVE_TO_SELF,2f
    ,TranslateAnimation.RELATIVE_TO_SELF,0
    ,TranslateAnimation.RELATIVE_TO_SELF,0
    ,TranslateAnimation.RELATIVE_TO_SELF,0);
  set.addAnimation(translate);
  AlphaAnimation alpha = new AlphaAnimation(0,1);
  set.addAnimation(alpha);
  set.setDuration(500);
  return set;
 }
 //隱藏減號的動畫
 private Animation getHiddenAnimation(){
  AnimationSet set = new AnimationSet(true);
  RotateAnimation rotate = new RotateAnimation(0,720,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);
  set.addAnimation(rotate);
  TranslateAnimation translate = new TranslateAnimation(
    TranslateAnimation.RELATIVE_TO_SELF,0
    ,TranslateAnimation.RELATIVE_TO_SELF,2f
    ,TranslateAnimation.RELATIVE_TO_SELF,0
    ,TranslateAnimation.RELATIVE_TO_SELF,0);
  set.addAnimation(translate);
  AlphaAnimation alpha = new AlphaAnimation(1,0);
  set.addAnimation(alpha);
  set.setDuration(500);
  return set;
 }

 //執(zhí)行動畫 只需給對應控件setAnimation然后調(diào)用setVisibility方法即可
 {
  ....
  tvMinus.setAnimation(getHiddenAnimation());
  tvMinus.setVisibility(View.GONE);
 }

拋物線動畫和上面的差不多可以分解成兩個平移動畫,不過兩個平移動畫的差值器一個線性一個加速而已,因為動畫界面跨度比較大所以需要在根部局內(nèi)寫,不能寫在列表的item中(這樣會顯示不全)。
代碼中的anim_mask_layout 即為整個布局文件的根布局,這里是一個RelativeLayout

實現(xiàn)過程:

1、首先點擊加號圖標,拿到控件在屏幕上的絕對坐標,回調(diào)activity顯示動畫

 int[] loc = new int[2];
 v.getLocationInWindow(loc);
 activity.playAnimation(loc);

2、創(chuàng)建動畫的控件并添加到根部局并在動畫結束后移除動畫view

 public void playAnimation(int[] start_location){
  ImageView img = new ImageView(this);
  img.setImageResource(R.drawable.button_add);
  setAnim(img,start_location);
 }
 //創(chuàng)建動畫 平移動畫直接傳遞偏移量 
 private Animation createAnim(int startX,int startY){
  int[] des = new int[2];
  imgCart.getLocationInWindow(des);

  AnimationSet set = new AnimationSet(false);

  Animation translationX = new TranslateAnimation(0, des[0]-startX, 0, 0);
  //線性插值器 默認就是線性
  translationX.setInterpolator(new LinearInterpolator());
  Animation translationY = new TranslateAnimation(0, 0, 0, des[1]-startY);
  //設置加速插值器
  translationY.setInterpolator(new AccelerateInterpolator());
  Animation alpha = new AlphaAnimation(1,0.5f);
  set.addAnimation(translationX);
  set.addAnimation(translationY);
  set.addAnimation(alpha);
  set.setDuration(500);

  return set;
 }
 //計算動畫view在根部局中的坐標 添加到根部局中
 private void addViewToAnimLayout(final ViewGroup vg, final View view,
          int[] location) {

  int x = location[0];
  int y = location[1];
  int[] loc = new int[2];
  vg.getLocationInWindow(loc);
  view.setX(x);
  view.setY(y-loc[1]);
  vg.addView(view);
 }
 //設置動畫結束移除動畫view 
 private void setAnim(final View v, int[] start_location) {

  addViewToAnimLayout(anim_mask_layout, v, start_location);
  Animation set = createAnim(start_location[0],start_location[1]);
  set.setAnimationListener(new Animation.AnimationListener() {
   @Override
   public void onAnimationStart(Animation animation) {

   }

   @Override
   public void onAnimationEnd(final Animation animation) {
    //直接remove可能會因為界面仍在繪制中成而報錯
    mHanlder.postDelayed(new Runnable() {
     @Override
     public void run() {
      anim_mask_layout.removeView(v);
     }
    },100);
   }

   @Override
   public void onAnimationRepeat(Animation animation) {

   }
  });
  v.startAnimation(set);
 }

4:底部彈出購物車清單

底部彈出的效果大家一定都很熟悉了,幾回每個項目中都會用的到,官方?jīng)]有提供簡單的控件實現(xiàn),一般都需要自己寫,不過要做到簡單流暢,便于移植推薦使用第三方庫,這里向大家推薦一個

bottomsheet

集成簡單,效果多樣這里簡單介紹一下使用方法

集成

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

使用

xml中使用BottomSheetLayout包裹彈出view時候的背景布局,BottomSheetLayout繼承自幀布局:

<com.flipboard.bottomsheet.BottomSheetLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/bottomSheetLayout"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 <LinearLayout
  android:orientation="horizontal"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <android.support.v7.widget.RecyclerView
   android:layout_width="100dp"
   android:id="@+id/typeRecyclerView"
   android:layout_height="match_parent">
  </android.support.v7.widget.RecyclerView>

  <se.emilsjolander.stickylistheaders.StickyListHeadersListView
   android:layout_width="match_parent"
   android:background="#fff"
   android:id="@+id/itemListView"
   android:layout_height="match_parent">
  </se.emilsjolander.stickylistheaders.StickyListHeadersListView>
 </LinearLayout>
</com.flipboard.bottomsheet.BottomSheetLayout>

代碼中使用很簡單

 //彈出View bottomSheet即是要彈出的view
 bottomSheetLayout.showWithSheetView(bottomSheet);

 //代碼隱藏view (點擊彈出view以外的地方可以隱藏彈出的view,向下滑動也可以)
 bottomSheetLayout.dismissSheet();

5:數(shù)據(jù)的同步

同步數(shù)據(jù),控制界面刷新應該是新手最容易繞彎的地方了,其實只要仔細一點也不難,這里簡單提供一種思路(并不一定適合你的項目).

 //商品列表
 private ArrayList<GoodsItem> dataList;
 //分類列表
 private ArrayList<GoodsItem> typeList;
 //已選擇的商品
 private SparseArray<GoodsItem> selectedList;
 //用于記錄每個分組選擇的數(shù)目
 private SparseIntArray groupSelect;

SparseArray這個類其實就是 HashMap< Integer,Object >

不過SparseArray既可以根據(jù)key查找Value,也可以根據(jù)位置查找value,性能比HashMap高,是官方推薦的替代類,
同樣SparseIntArray 其實是HashMap< Integer,Integer> 的替代者。

Activity里實現(xiàn)了下面幾個方法,用于數(shù)據(jù)統(tǒng)一管理
列表中顯示的商品購買數(shù)量統(tǒng)一從activity獲取,商品的加減統(tǒng)一調(diào)用Activity的方法然后notifiDatasetChanged,由于代碼不少具體的還是看源碼吧

 /**
  * Item代表商品的購買數(shù)量加一
  * @param item
  * @param refreshGoodList 是否刷新商品list
  */
 public void add(GoodsItem item,boolean refreshGoodList){

  int groupCount = groupSelect.get(item.typeId);
  if(groupCount==0){
   groupSelect.append(item.typeId,1);
  }else{
   groupSelect.append(item.typeId,++groupCount);
  }

  GoodsItem temp = selectedList.get(item.id);
  if(temp==null){
   item.count=1;
   selectedList.append(item.id,item);
  }else{
   temp.count++;
  }
  update(refreshGoodList);
 }
 /**
  * Item商品的購買數(shù)量減一
  * @param item
  * @param refreshGoodList 是否刷新商品list
  */
 public void remove(GoodsItem item,boolean refreshGoodList){

  int groupCount = groupSelect.get(item.typeId);
  if(groupCount==1){
   groupSelect.delete(item.typeId);
  }else if(groupCount>1){
   groupSelect.append(item.typeId,--groupCount);
  }

  GoodsItem temp = selectedList.get(item.id);
  if(temp!=null){
   if(temp.count<2){
    selectedList.remove(item.id);
   }else{
    item.count--;
   }
  }
  update(refreshGoodList);
 }

 /**
  * 刷新界面 總價、購買數(shù)量等
  * @param refreshGoodList 是否刷新商品list
  */
 private void update(boolean refreshGoodList){
  ...
 }

 //根據(jù)商品id獲取當前商品的采購數(shù)量
 public int getSelectedItemCountById(int id){
  GoodsItem temp = selectedList.get(id);
  if(temp==null){
   return 0;
  }
  return temp.count;
 }
 //根據(jù)類別Id獲取屬于當前類別的數(shù)量
 public int getSelectedGroupCountByTypeId(int typeId){
  return groupSelect.get(typeId);
 }

具體邏輯還是看代碼吧,也許有更簡單的實現(xiàn)。。。

Demo下載地址,下載到的文件是個AS module,你可以在自己新建的工程中Import Module.

源碼下載:Android仿外賣購物車功能

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

最新評論

都兰县| 寻乌县| 安达市| 泽库县| 香河县| 通化市| 太原市| 抚远县| 四平市| 康保县| 根河市| 应用必备| 汉寿县| 乌鲁木齐市| 陕西省| 长葛市| 黑河市| 青河县| 吉隆县| 通许县| 长子县| 定安县| 贵溪市| 汉阴县| 咸阳市| 淅川县| 西吉县| 永兴县| 荃湾区| 威信县| 武夷山市| 图片| 东明县| 石河子市| 贵溪市| 清镇市| 河北区| 郎溪县| 武安市| 土默特右旗| 吴川市|