溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android如何實(shí)現(xiàn)仿京東手機(jī)端類別頁(yè)

發(fā)布時(shí)間:2021-06-28 09:25:53 來(lái)源:億速云 閱讀:148 作者:小新 欄目:移動(dòng)開(kāi)發(fā)

這篇文章主要介紹Android如何實(shí)現(xiàn)仿京東手機(jī)端類別頁(yè),文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

京東手機(jī)端的類別標(biāo)簽頁(yè), 是一個(gè)左側(cè)滑動(dòng)可選擇類別, 右側(cè)一個(gè)類別明細(xì)的列表聯(lián)動(dòng)頁(yè)面. 當(dāng)用戶選擇左側(cè)選項(xiàng), 可在右側(cè)顯示更多選項(xiàng)來(lái)選擇. 實(shí)現(xiàn)方式也不少. 最常見(jiàn)的當(dāng)然是左側(cè)和右側(cè)各一個(gè)Fragment, 左側(cè)Fragment放置ListView, 右側(cè)放顯示類別明細(xì)的Fragment. 如果覺(jué)得頁(yè)面包含的Fragment太多, 左側(cè)直接給一個(gè)ListView就可以了.不影響效果.

效果圖:

Android如何實(shí)現(xiàn)仿京東手機(jī)端類別頁(yè)

例子中值得注意的三點(diǎn):

  • 左側(cè)列表點(diǎn)擊某個(gè)Item可以自動(dòng)上下滑動(dòng),使所點(diǎn)擊的item自動(dòng)移至列表中間

  • 點(diǎn)擊item后保留背景色不變

  • 右側(cè)布局

針對(duì)上面三個(gè)點(diǎn),這里采取如下的解決方法:

  • 計(jì)算可見(jiàn)列表的可見(jiàn)首項(xiàng)或末項(xiàng)position值,使用smoothScrollToPosition()方法實(shí)現(xiàn)滑動(dòng)

  • 自定義列表selector按下和松開(kāi)的背景色,在adapter去更新并控制item的背景色

  • 右側(cè)布局,采用Fragment是最好的. 里面使用ScrollView裝載所有數(shù)據(jù),可以動(dòng)態(tài)的addView(),removeView(), 網(wǎng)格布局使用GridView. 由于Fragment, 所以更新數(shù)據(jù)和更新View都非常方便, 所以例子中直接用靜態(tài)頁(yè)面模擬數(shù)據(jù)了.

重在通過(guò)簡(jiǎn)單的例子解釋這種實(shí)現(xiàn)思路, 當(dāng)然實(shí)現(xiàn)不是唯一的.

然后,我們先來(lái)模擬右側(cè)的Fragment數(shù)據(jù),一看就懂的代碼:

public class JDFragment extends Fragment{
  String TAG = "JDFragment";
  private View rootView = null;
  private LinearLayout llayout_main = null;
  private TextView tv = null;

  private LinearLayout.LayoutParams lp_gd = null;
  private LinearLayout.LayoutParams lp_tv = null;
  private ArrayList<Category> itemList = null;
  private GDAdapter adapter = null;


  @Override
  public void onAttach(Activity activity)
  {
    Log.e(TAG, "onAttach...");
    super.onAttach(activity);
  }

  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    Log.e(TAG, "onCreate...");
    super.onCreate(savedInstanceState);
  }


  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState)
  {
    Log.e(TAG, "onCreateView...");
    rootView = inflater.inflate(R.layout.jd_frg_main, null);
    llayout_main = (LinearLayout) rootView.findViewById(R.id.llayout_jd_frg_main);
    tv = (TextView) rootView.findViewById(R.id.tv_jd_frg_main);

    updateTitle();

    //模擬數(shù)據(jù)
    for(int i=0; i<2; i++)
    {
      setData();     
    }

    return rootView;
  }

  protected void updateTitle()
  {
    if(getArguments() != null)
    {
      updateTitle(getArguments().getString("name"));
    }
  }

  protected void updateTitle(String title)
  {
    if(tv != null)
    {
      tv.setText(title);
    }
  }

  private void setData()
  {
    if(itemList == null)
    {
      itemList = new ArrayList<Category>();
      for(int i=1; i<11; i++)
      {
        itemList.add(new Category("選項(xiàng) " + i, ""+i));
      }
    }

    //高度60dp+行距8dp = 68dp
    int heightUnit = (int)TypedValue
        .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 68, getResources().getDisplayMetrics());
    int height;

    //計(jì)算Gridview總高度
    if(itemList.size() % 3 == 0)
    {
      height = (itemList.size()/3 + 2)*heightUnit;
    }
    else{
      height = (itemList.size()/3 + 1)*heightUnit;
    }

    if(lp_gd == null)
      lp_gd = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, height);

    if(lp_tv == null)
      lp_tv = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT
          , (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP
              , 30, getResources().getDisplayMetrics()));

    TextView tv_title = new TextView(getActivity());
    tv_title.setLayoutParams(lp_tv);
    tv_title.setText("組一");
    llayout_main.addView(tv_title);

    GridView gridView = new GridView(getActivity());
    gridView.setNumColumns(3);
    gridView.setVerticalSpacing(8);
    gridView.setLayoutParams(lp_gd);

    adapter = new GDAdapter(getActivity(), itemList,R.drawable.cate);
    gridView.setAdapter(adapter);
    llayout_main.addView(gridView);
  }


  @Override
  public void onActivityCreated(Bundle savedInstanceState)
  {
    Log.e(TAG, "onActivityCreated...");
    super.onActivityCreated(savedInstanceState);
  }

  @Override
  public void onStart()
  {
    Log.e(TAG, "onStart...");
    super.onStart();
  }

  @Override
  public void onResume()
  {
    Log.e(TAG, "onResume...");
    super.onResume();
  }

  @Override
  public void onPause()
  {
    Log.e(TAG, "onPause...");
    super.onPause();
  }

  @Override
  public void onStop()
  {
    Log.e(TAG, "onStop...");
    super.onStop();
  }

  @Override
  public void onDestroyView()
  {
    Log.e(TAG, "onDestroyView...");
    super.onDestroyView();
  }

  @Override
  public void onDestroy()
  {
    Log.e(TAG, "onDestroy...");
    super.onDestroy();
  }

  @Override
  public void onDetach()
  {
    Log.e(TAG, "onDetach...");
    super.onDetach();
  }

  static class GDAdapter extends BaseAdapter
  {
    Context context;
    List<Category> results;
    int imageId;
    ViewHolder holder = null;

    public GDAdapter(Context context, List<Category> results,int imageId) {
      this.context = context;
      this.results = results;
      this.imageId = imageId;
    }

    @Override
    public int getCount() {
      // TODO Auto-generated method stub
      return results.size();
    }

    @Override
    public Object getItem(int position) {
      // TODO Auto-generated method stub
      return results.get(position);
    }


    @Override
    public long getItemId(int position) {
      // TODO Auto-generated method stub
      return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      Category c = (Category)getItem(position);

      if(convertView == null)
      {
        holder = new ViewHolder();
        convertView = LayoutInflater.from(context).inflate(R.layout.jd_item, null);
        holder.tv = (TextView) convertView.findViewById(R.id.tv_jd_item);
        holder.imv = (ImageView) convertView.findViewById(R.id.imv_jd_item);
      }
      else
      {
        holder = (ViewHolder) convertView.getTag();
      }
      convertView.setTag(holder);

      holder.tv.setText(c.getName());
      holder.imv.setImageResource(imageId);

      return convertView;
    }

    class ViewHolder
    {
      TextView tv;
      ImageView imv;
    }
  }

}

JDFragment的布局文件, jd_frg_main.xml:

<?xml version="1.0" encoding="utf-8" ?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="#FFFFFF"
  >
  <TextView 
    android:id="@+id/tv_jd_frg_main"
    android:layout_width="match_parent"
    android:layout_height="25dp"
    android:text="Fragment"
    android:textSize="16sp"
    android:background="#EEEEEE"
    />
  <ScrollView 
    android:id="@+id/scrlayout_jd_frg_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/tv_jd_frg_main"
    android:overScrollMode="never"
    >
    <LinearLayout 
      android:id="@+id/llayout_jd_frg_main"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:orientation="vertical"
      />
  </ScrollView>


</RelativeLayout>

將所有數(shù)據(jù)放在ScrollView的線性布局中,使用Fragment作為容器, 可以根據(jù)需要ADD, Remove和Update數(shù)據(jù)和View. 到這里右側(cè)頁(yè)面的簡(jiǎn)單模擬實(shí)現(xiàn)就結(jié)束了,都是一目了然的代碼.

然后就是實(shí)現(xiàn)左側(cè)列表了,先是列表中簡(jiǎn)單的自定義Adapter, MyAdapter:

public class MyAdapter extends BaseAdapter
{
  private Context context;
  private List<Category> results;
  private int imageId;
  private ViewHolder holder = null;
  private int selectedId;

  public MyAdapter(Context context, List<Category> results,int imageId) {
    this.context = context;
    this.results = results;
    this.imageId = imageId;
  }

  @Override
  public int getCount() {
    // TODO Auto-generated method stub
    return results.size();
  }

  @Override
  public Object getItem(int position) {
    // TODO Auto-generated method stub
    return results.get(position);
  }


  @Override
  public long getItemId(int position) {
    // TODO Auto-generated method stub
    return position;
  }

  public void setSelected(int position)
  {
    this.selectedId = position;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    Category c = (Category)getItem(position);

    if(convertView == null)
    {
      holder = new ViewHolder();
      convertView = LayoutInflater.from(context).inflate(R.layout.jd_item, null);
      holder.tv = (TextView) convertView.findViewById(R.id.tv_jd_item);
      holder.imv = (ImageView) convertView.findViewById(R.id.imv_jd_item);
    }
    else
    {
      holder = (ViewHolder) convertView.getTag();
    }

    if(position == selectedId)
    {
      convertView.setBackgroundResource(R.drawable.sele_true);
    }
    else
    {
      convertView.setBackgroundResource(R.drawable.sele_false);
    }

    holder.tv.setText(c.getName());
    holder.imv.setImageResource(imageId);
    convertView.setTag(holder);

    return convertView;
  }

  class ViewHolder
  {
    TextView tv;
    ImageView imv;
  }
}

然后是主Activity了, 在里面對(duì)可見(jiàn)ListView的item位置進(jìn)行計(jì)算, 并進(jìn)行滑動(dòng)處理. 當(dāng)用戶點(diǎn)擊偏上的item, 列表就往下滑動(dòng), 加載頂部更多的item; 當(dāng)用戶點(diǎn)擊偏下的item, 列表就往上滑動(dòng), 加載底部更多的item.

同時(shí)我們自定義按下和松開(kāi)時(shí)的背景文件放在drawable, 隨便一個(gè)shape就可以了. 然后點(diǎn)擊某個(gè)item的position時(shí), 在adapter中判斷是否目標(biāo)item, 是就設(shè)置按下背景色 - 白色, 否則就是正常的背景色 - 灰色.

/**
 * 仿京東類別頁(yè)
 * @author AlexTam
 */
public class JDActivity extends FragmentActivity{
  private ListView lv_main = null;
  private EditText et_search = null;

  private ArrayList<Category> itemList = new ArrayList<Category>(); 
  private MyAdapter adapter = null;
  //可見(jiàn)列表項(xiàng)的數(shù)量
  private int visibleCount = 0;
  //上次點(diǎn)擊的位置
  private int lastPosition = 0;
  private int ce = 0;
  //實(shí)際列表是否超出屏幕
  private boolean isOut = true;
  private JDFragment fragment = null;

  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.jd_main);

    init();
  }


  private void init()
  {
    lv_main = (ListView) findViewById(R.id.lv_main);
    et_search = (EditText) findViewById(R.id.et_search);

    for(int i=1; i<21; i++)
    {
      itemList.add(new Category("選項(xiàng) " + i, ""+i));
    }

    adapter = new MyAdapter(this, itemList,R.drawable.ic_launcher);
    lv_main.setAdapter(adapter);
    lv_main.setOnItemClickListener(new MyOnItemOnClick());
    lv_main.setSelector(R.color.pink);

    //模擬右側(cè)標(biāo)簽頁(yè)
    fragment = new JDFragment();
    Bundle bundle = new Bundle();
    bundle.putString("name", "c1");
    fragment.setArguments(bundle);
    FragmentManager fm = getSupportFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.flayout_main, fragment, "c0").commit();

    adapter.setSelected(0);
    adapter.notifyDataSetChanged();
  }

  private class MyOnItemOnClick implements OnItemClickListener
  {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
        long id) 
    {
      //計(jì)算滑動(dòng)
      if(visibleCount == 0)
      {
        visibleCount = lv_main.getChildCount();
        if(visibleCount == itemList.size())
          isOut = false;
        else
        {
          ce = visibleCount/2;
        }
      }

      if(position <= (parent.getFirstVisiblePosition() + ce))
      {  //上移
        lv_main.smoothScrollToPosition(position - ce);
      }
      else
      {  //下移
        if((parent.getLastVisiblePosition() + ce + 1) <= parent.getCount())
        {
          lv_main.smoothScrollToPosition(position + ce);
        }
        else
        {
          lv_main.smoothScrollToPosition(parent.getCount()-1);
        }

      }

      lastPosition = position;

      adapter.setSelected(position);
      adapter.notifyDataSetChanged();

      //更新右側(cè)標(biāo)簽頁(yè)的標(biāo)題
      fragment.updateTitle("c" + (position+1));
    }

  }


  /**
   * 選項(xiàng)對(duì)象
   */
  static class Category
  {
    private String name;
    private String id;

    Category(String name,String id)
    {
      this.name = name;
      this.id = id;
    }

    public String getName()
    {
      return this.name;
    }
  }



}

OK, 到此效果就出來(lái)了. 好簡(jiǎn)單吧!

以上是“Android如何實(shí)現(xiàn)仿京東手機(jī)端類別頁(yè)”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI