Android 仿2016版京东筛选

京东筛选更新了,很好,很炫酷。那什么,我们也不差是吧,于是就有了这个demo。话不多说,先看图,不想看代码的朋友,直接点底部下demo。

图1

图1里面呢,就两点,弹出的PopupWindow的高度为屏幕高的一半,另一半为半透明高端黑,简单点就用weight属性来写,方便快捷。然后在上半部分写个GridView,在GridView的底部有个LinearLayout,用来放俩Button,但是Button比较难处理布局,本着高仿的原则,我还是用的TextView。哈哈,机智如我。布局很简单,反正我是没怎么费脑筋就给搞出来的。下面来看看PopupWindow的核心代码:

PricePopup.java

变量

    private View contentView;
    private GridView grid;
    private TextView reset;
    private TextView ok;
    private PopupAdapter adapter;
    private List<Vo> data;

主方法

    public PricePopup(final Activity context, final List<Vo> data) {
        this.data = data;
        adapter = new PopupAdapter(context);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        contentView = inflater.inflate(R.layout.popup, null);
        grid = (GridView) contentView.findViewById(R.id.grid);
        reset = (TextView) contentView.findViewById(R.id.reset);
        ok = (TextView) contentView.findViewById(R.id.ok);
        grid.setAdapter(adapter);
        grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
                data.get(position).setChecked(!data.get(position).isChecked());
                for (int i = 0; i < data.size(); i++) {
                    if (i == position) {
                        continue;
                    }
                    data.get(i).setChecked(false);
                }
                Toast.makeText(context, data.get(position).getStr2(), Toast.LENGTH_SHORT).show();
                adapter.notifyDataSetChanged(data);
            }
        });

        int h = context.getWindowManager().getDefaultDisplay().getHeight();
        int w = context.getWindowManager().getDefaultDisplay().getWidth();
        this.setContentView(contentView);
        this.setWidth(w);
        this.setHeight(h);
        ColorDrawable dw = new ColorDrawable(00000000);
        this.setBackgroundDrawable(dw);
        this.setFocusable(true);
        this.setOutsideTouchable(false);
        this.update();
    }

展示popupwindow的方法

    public void showPricePopup(View parent, final List<Vo> data) {
        if (!this.isShowing()) {
            this.showAsDropDown(parent);
            adapter.notifyDataSetChanged(data);
        } else {
            this.dismiss();
        }
    }
图2

Adapter就不放了,demo里面有的。接下来,图2里面的就比较复杂了。还是先看布局吧:

左边灰色透明背景

    <View
        android:id="@+id/popup_goods_noview"
        android:layout_width="48dp"
        android:layout_height="match_parent"
        android:background="#88000000" />

由于是采用水平方向的线性布局,所以右边布局直接写宽度为match_parent就好。

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff">
   //省略服务和价格区间布局代码,直接上重要的部分,这里是采用一个大的listview来放item
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <ListView
                    android:id="@+id/selection_list"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:divider="@null"
                    android:dividerHeight="14dp"
                    android:orientation="vertical"
                    android:scrollbars="none" />

            </RelativeLayout>
//底部重置和确定按钮
        <LinearLayout
            android:id="@+id/filter_layout"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:layout_alignParentBottom="true"
            android:background="#ffffff"
            android:orientation="vertical">
//并不华丽的分割线
            <View
                android:layout_width="match_parent"
                android:layout_height="1px"
                android:background="#cccccc" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:gravity="center_vertical"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/filter_reset"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="center"
                    android:text="重置" />

                <TextView
                    android:id="@+id/filter_sure"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="#ff0033"
                    android:gravity="center"
                    android:text="确定"
                    android:textColor="#ffffff" />
            </LinearLayout>
        </LinearLayout>
    </RelativeLayout>

PopupWindow代码:

    //变量
    private View contentView;
    private Context context;
    private View goodsNoView;
    private GridView serviceGrid;
    private ListView selectionList;
    private TextView filterReset;
    private TextView filterSure;
    private GoodsAttrListAdapter adapter;
    private GoodsAttrsAdapter serviceAdapter;
    private List<SaleAttributeNameVo> itemData;
    private List<SaleAttributeVo> serviceList;
    private String[] serviceStr = new String[]{"仅看有货", "促销", "手机专享"};

主方法

    public FilterPopupWindow(final Activity context) {
        this.context = context;
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        contentView = inflater.inflate(R.layout.popup_goods_details, null);
        goodsNoView = contentView.findViewById(R.id.popup_goods_noview);
        serviceGrid = (GridView) contentView.findViewById(R.id.yuguo_service);
        selectionList = (ListView) contentView.findViewById(R.id.selection_list);
        filterReset = (TextView) contentView.findViewById(R.id.filter_reset);
        filterSure = (TextView) contentView.findViewById(R.id.filter_sure);

        goodsNoView.setOnClickListener(new CancelOnClickListener());
        contentView.setOnKeyListener(new OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) {
                    dismiss();
                }
                return true;
            }
        });
        serviceList = new ArrayList<SaleAttributeVo>();
        for (int i = 0; i < serviceStr.length; i++) {
            SaleAttributeVo vo = new SaleAttributeVo();
            vo.setValue(serviceStr[i]);
            serviceList.add(vo);
        }
        serviceAdapter = new GoodsAttrsAdapter(context);
        serviceGrid.setAdapter(serviceAdapter);
        serviceAdapter.notifyDataSetChanged(true, serviceList);

gridview监听

        serviceGrid.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
                //设置当前选中的位置的状态为非。
                serviceList.get(arg2).setChecked(!serviceList.get(arg2).isChecked());
                for (int i = 0; i < serviceList.size(); i++) {
                    //跳过已设置的选中的位置的状态
                    if (i == arg2) {
                        continue;
                    }
                    serviceList.get(i).setChecked(false);
                }
                serviceAdapter.notifyDataSetChanged(true, serviceList);
            }
        });

数据

        itemData = new ArrayList<SaleAttributeNameVo>();
        adapter = new GoodsAttrListAdapter(context, itemData);
        selectionList.setAdapter(adapter);
        //为了便于看码,这里只写了一条数据
        String str = "["
                + "{\"nameId\":\"V2QASD\",\"saleVo\":["
                + "{\"value\":\"2核\",\"goods\":null,\"goodsAndValId\":\"C6VOWQ\",\"checkStatus\":\"1\"},"
                + "{\"value\":\"4核\",\"goods\":null,\"goodsAndValId\":\"C6VOWQ\",\"checkStatus\":\"0\"},"
                + "{\"value\":\"6核\",\"goods\":null,\"goodsAndValId\":\"C6VOWQ\",\"checkStatus\":\"0\"},"
                + "{\"value\":\"8核\",\"goods\":null,\"goodsAndValId\":\"C6VOWQ\",\"checkStatus\":\"0\"}"
                + "],\"name\":\"CPU\"}";
        JSONArray json = null;
        try {
            json = new JSONArray(str);
            refreshAttrs(json);
        } catch (JSONException e) {
            e.printStackTrace();
        }

重置的点击监听,将所有选项全设为false

        filterReset.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                for (int i = 0; i < itemData.size(); i++) {
                    for (int j = 0; j < itemData.get(i).getSaleVo().size(); j++) {
                        itemData.get(i).getSaleVo().get(j).setChecked(false);
                    }
                }
                adapter.notifyDataSetChanged();
            }
        });

确定的点击监听,将所有已选中项列出

        filterSure.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                String str = "";
                for (int i = 0; i < itemData.size(); i++) {
                    for (int j = 0; j < itemData.get(i).getSaleVo().size(); j++) {
                        if (itemData.get(i).getSaleVo().get(j).isChecked()) {
                            str = str + itemData.get(i).getSaleVo().get(j).getValue();
                        }
                    }
                }
                Toast.makeText(FilterPopupWindow.this.context, str, Toast.LENGTH_SHORT).show();
            }
        });

设置popupwindow属性

        this.setContentView(contentView);
        this.setWidth(LayoutParams.MATCH_PARENT);
        this.setHeight(LayoutParams.MATCH_PARENT);
        ColorDrawable dw = new ColorDrawable(00000000);
        this.setBackgroundDrawable(dw);
        this.setFocusable(true);
        this.setOutsideTouchable(false);
        this.update();

    }

刷新商品属性

    public void refreshAttrs(JSONArray json) throws JSONException {
        itemData.clear();
        for (int i = 0; i < json.length(); i++) {
            SaleAttributeNameVo saleName = new SaleAttributeNameVo();
            JSONObject obj = (JSONObject) json.opt(i);
            saleName.setName(obj.getString("name"));
            List<SaleAttributeVo> list = new ArrayList<SaleAttributeVo>();
            net.sf.json.JSONArray array = new net.sf.json.JSONArray();
            array = net.sf.json.JSONArray.fromObject(obj.getString("saleVo"));
            for (int j = 0; j < array.size(); j++) {
                net.sf.json.JSONObject object = array.getJSONObject(j);
                SaleAttributeVo vo = new SaleAttributeVo();
                vo.setGoods(object.getString("goods"));
                vo.setValue(object.getString("value"));
                vo.setGoodsAndValId(object.getString("goodsAndValId"));
                if ("1".equals(object.getString("checkStatus"))) {
                    vo.setChecked(true);
                } else {
                    vo.setChecked(false);
                }
                list.add(vo);
            }
            saleName.setSaleVo(list);
            // 是否展开
            saleName.setNameIsChecked(false);
            itemData.add(saleName);
        }
        adapter.notifyDataSetChanged();
    }

处理popupwindow消失的事件

    public class CancelOnClickListener implements OnClickListener {
        @Override
        public void onClick(View v) {
            dismiss();
        }
    }

    public boolean onKeyDown(Context context, int keyCode, KeyEvent event) {
        this.context = context;
        if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) {
            dismiss();
        }
        return true;
    }

显示popupwindow

    public void showFilterPopup(View parent) {
        if (!this.isShowing()) {
            this.showAsDropDown(parent);
        } else {
            this.dismiss();
        }
    }

额,好像代码有点长,没办法,东西有这么多的。看Adapter吧:
这个是单选的:

属性listview的适配器

变量

    private Context context;
    private List<SaleAttributeNameVo> data;

主方法

    public GoodsAttrListAdapter(Context context, List<SaleAttributeNameVo> data) {
        this.context = context;
        this.data = data;
    }

重点来了

    @Override
    public View getView(final int position, View v, ViewGroup parent) {
        final MyView myView;
        if (v == null) {
            myView = new MyView();
            v = View.inflate(context, R.layout.item_goods_attr_list, null);
            myView.name = (TextView) v.findViewById(R.id.attr_list_name);
            myView.img = (ImageView) v.findViewById(R.id.attr_list_img);
            myView.grid = (GridView) v.findViewById(R.id.attr_list_grid);
            myView.grid.setSelector(new ColorDrawable(Color.TRANSPARENT));
            v.setTag(myView);
        } else {
            myView = (MyView) v.getTag();
        }
        myView.name.setText(data.get(position).getName());
        final GoodsAttrsAdapter adapter = new GoodsAttrsAdapter(context);
        myView.grid.setAdapter(adapter);
        adapter.notifyDataSetChanged(data.get(position).isNameIsChecked(), data.get(position).getSaleVo());

展开隐藏更多属性

        myView.img.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (data.get(position).isNameIsChecked()) {
                    ((ImageView) v).setImageResource(R.drawable.sort_common_up);
                } else {
                    ((ImageView) v).setImageResource(R.drawable.sort_common_down);
                }
                adapter.notifyDataSetChanged(data.get(position).isNameIsChecked(), data.get(position).getSaleVo());
                data.get(position).setNameIsChecked(!data.get(position).isNameIsChecked());
            }
        });

item选择事件

        myView.grid.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
                //设置当前选中的位置的状态为非。
                data.get(position).getSaleVo().get(arg2).setChecked(!data.get(position).getSaleVo().get(arg2).isChecked());
                for (int i = 0; i < data.get(position).getSaleVo().size(); i++) {
                    //跳过已设置的选中的位置的状态
                    if (i == arg2) {
                        continue;
                    }
                    data.get(position).getSaleVo().get(i).setChecked(false);
                }
                if (!data.get(position).isNameIsChecked()) {
                    myView.img.setImageResource(R.drawable.sort_common_up);
                } else {
                    myView.img.setImageResource(R.drawable.sort_common_down);
                }
                adapter.notifyDataSetChanged(!data.get(position).isNameIsChecked(), data.get(position).getSaleVo());
            }
        });
        return v;
    }

这个你懂的

    static class MyView {
        public TextView name;
        public ImageView img;
        public GridView grid;
    }

这个是多选,只是myView.grid.setOnItemClickListener()里面的方法不一样,单选的是把其他的选中状态设置成false了,没往代码里面传了哈,需要的朋友在这里看。

        myView.grid.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
                //设置当前选中的位置的状态为非。
                data.get(position).getSaleVo().get(arg2).
                    setChecked(!data.get(position).getSaleVo().get(arg2).isChecked());
                adapter.notifyDataSetChanged(data.get(position).isNameIsChecked(), 
                    data.get(position).getSaleVo());
            }
        });
        return v;
    }

我把监听写这里面的。内部Adapter如下:
getView

    @Override
    public View getView(final int position, View v, ViewGroup parent) {
        final MyView myView;
        if (v == null) {
            myView = new MyView();
            v = View.inflate(context, R.layout.item_goods_attrs, null);
            myView.attr = (TextView) v.findViewById(R.id.attr_name);
            v.setTag(myView);
        } else {
            myView = (MyView) v.getTag();
        }
        myView.attr.setText(data.get(position).getValue());
        /**
         * 根据选中状态来设置item的背景和字体颜色
         */
        if (data.get(position).isChecked()) {
            myView.attr.setBackgroundResource(R.drawable.goods_attr_selected_shape);
            myView.attr.setTextColor(Color.WHITE);
        } else {
            myView.attr.setBackgroundResource(R.drawable.goods_attr_unselected_shape);
            myView.attr.setTextColor(Color.GRAY);
        }
        return v;
    }

这个你懂的

    static class MyView {
        public TextView attr;
    }

复写notifyDataSetChanged()

    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
    }

    public void notifyDataSetChanged(boolean isUnfold,
                                     final List<SaleAttributeVo> tempData) {
        if (tempData == null || 0 == tempData.size()) {
            return;
        }
        data.clear();
        // 如果是展开的,则加入全部data,反之则只显示3条
        if (isUnfold) {
            data.addAll(tempData);
        } else {
            data.add(tempData.get(0));
            data.add(tempData.get(1));
            data.add(tempData.get(2));
        }
        notifyDataSetChanged();
    }

其中的isNameIsChecked()其实是因为懒,没有改名字,这个是判断是否需要子属性展开的。

好了,就酱。demo放出:
http://download.csdn.net/detail/u013806766/9579156


突然还想起个问题,之前用Android Studio没有配好Gradle,于是就用的Eclipse先写的,导出的时候选的Gradle,再用Android Studio编辑的,结果报错了,大概意思就是Gradle版本的问题,于是乎:

gradle编译时失败报错,需将 项目名称\gradle\wrapper\gradle-wrapper.properties里的

distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip

改为

distributionUrl=http\://services.gradle.org/distributions/gradle-2.10-all.zip

后面的数字即开发环境配置中gradle的版本

本文于2017年5月25日重新编辑,之前不会用简书的markdown,也没有时间去了解。最近重新去了解了一下,于是,将代码补全,也尽量将注释写的清楚些,方便大家阅读。如有疑问,请留言。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,395评论 25 707
  • 太长了,还是转载吧...今天在看博客的时候,无意中发现了@Trinea在GitHub上的一个项目Android开源...
    庞哈哈哈12138阅读 20,134评论 3 283
  • 今天闲了许久,身体闲着,思维也闲着,感觉最近的身体灵魂一直懒着。人应该在不断成长,而我最近却忘了,年轻又不算,像是...
    如貳阅读 176评论 0 0
  • 《人民的名义》最后领导找吴老师谈完话,对吴老师来讲,这也算是一个仪式性的结束吧,在她高傲又挣扎的人生中算作一个...
    木之夕阅读 1,142评论 2 7
  • 越来越深刻的理解到,人与人是有差距的。这也导致了事物的参差多态。导致阶层的产生。比如有人住别墅,有人住出租屋。有小...
    c1dd5a05d5c8阅读 200评论 0 0