安卓Intent、Bundle的使用以及RecyclerView、ListView的应用

一、实验题目

Intent、Bundle的使用以及RecyclerView、ListView的应用

二、实现内容

本次实验模拟实现一个健康食品列表,有两个界面,第一个界面用于呈现食品列表 如下所示
此处输入图片的描述
数据在"manual/素材"目录下给出。
点击右下方的悬浮按钮可以切换到收藏夹
img2
上面两个列表点击任意一项后,可以看到详细的信息:
此处输入图片的描述


三、课堂实验结果

(1)实验截图

1、主界面
此处输入图片的描述

2、点击一个食品进入详情界面
此处输入图片的描述

3、点击收藏按钮
此处输入图片的描述

4、进入收藏夹栏
此处输入图片的描述

5、长按收藏栏夹中食品
此处输入图片的描述

6、点击确定
此处输入图片的描述

7、点击星星
此处输入图片的描述

8、长按食品栏删除

(2)实验步骤以及关键代码

1、设置主界面,由一个RecyclerView和一个ListView以及一个FloatingActionButton组成。一开始启动界面为RecyclerView,暂时设置ListView属性为gone。

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

    <ListView
        android:visibility="gone"
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

2、设置RecyclerView。首先获取设置RecyclerView,使用setLayoutManager设置布局属性。然后要先自定义RecyclerView.ViewHolder。ViewHolder通常出现在适配器里,为的是listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。使用一个SparseArray数组存储listItem中的子View。

 private SparseArray<View> views;
    private View view;

    public MyViewHolder(Context _context, View _view, ViewGroup _viewGroup){
        super(_view);
        view = _view;
        views = new SparseArray<View>();
    }

注意ViewHolder尚未将子View缓存到SparseArray数组中时,仍然需要通过findViewById()创建View对象,如果已缓存,直接返回即可。

 public <T extends View> T getView(int _viewId) {
        View _view = views.get(_viewId);
        if (_view == null) {
            // 创建view
            _view = view.findViewById(_viewId);
            // 将view存入views
            views.put(_viewId, _view);
        }
        return (T)_view;
    }

之后需要自定义一个adapter。Adapter扮演着两个角色,一是根据不同ViewType创建与之相应的Item-Layout,二是访问数据集合并将数据绑定到正确的View上。因此需要重写一下两个函数。
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)创建Item视图,并返回相应的ViewHolder。
public void onBindViewHolder(final MyViewHolder holder, int position)绑定数据到正确的Item视图上。
convert函数是一个抽象方法,在声明adapter时需要实现它。作用是将数据绑定到RecyclerView的各个控件中。

final MyRecyclerViewAdapter myAdapter = new MyRecyclerViewAdapter<Map<String,String>>(MainActivity.this, R.layout.items, data) {
            @Override
            public void convert(MyViewHolder holder, Map<String,String> s) {
                TextView name = holder.getView(R.id.name);
                name.setText(s.get("name"));
                TextView first = holder.getView(R.id.ID);
                first.setText(s.get("ID"));
            }
        };

RecyclerView没有OnItemClickListener方法,需要在Adapter中实现。方法为:在Adapter中设置一个监听器,当itemView被点击时,调用该监听器并且将itemView的position作为参数传递出去。先添加接口

public interface OnItemClickListener{
        void onClick(int position);
        void onLongClick(int position);
    }

    public void setOnItemClickListener(OnItemClickListener _onItemClickListener) {
        this.onItemClickListener = _onItemClickListener;
    }

然后在onBindViewHolder()中添加重写函数。
3、设置ListView。ListView的原理和RecyclerView类似。这里使用了simpleadapter
构造一个SimpleAdapter,需要以下的参数:

1.Context context:上下文,这个是每个组件都需要的,它指明了SimpleAdapter关联的View的运行环境,也就是我们当前的Activity。

2.List<? extends Map

先创建一个simpleAdapter

    simpleAdapter = new SimpleAdapter(this,data,R.layout.shoplist,
           new String[] {"icon","itemname"},new int[]{R.id.Icon,R.id.Name});

然后用setAdapter函数设置adapter
之后要给listview设定点击函数,分别为单击和长按事件。

4、现在要在点击函数中加上页面跳转以及数据传递。在recycleview中绑定的是一个List<Map<String,String>>链表,分别保存了标签和名称。我这里传递的数据是该列表项所处的位置以及名称。所有的信息保存为一个string数组,然后检测该列表项的名称匹配数组中的位置,将该位置和名称新建一个bundle,再通过intent传入。

               Bundle bundle = new Bundle();
               bundle.putInt("position",index);
               bundle.putString("name",_name);
               intent.putExtras(bundle);
               startActivityForResult(intent,1);

5、在详情页面内,使用getIntent()函数来接收信息,用getExtra获取bundle,然后判断该位置属于哪个食品,再绑定信息到各个控件中。

Intent intent=getIntent();
        Bundle bundle =intent.getExtras();
        String na=bundle.getString("name");

6、之后要进行详情页面的布局设计。我这里选择的是LinearLayout,把整个布局分为三块RelativeLayout。要设置顶部占三分之一,需要将整个LinearLayout的weightSum设为3,把顶部的RelativeLayout的layout_weight设为1.使用layout_alignParentLeft设置左对齐,底部对齐同理。要使得垂直居中需要设置layout_centerVertical属性为true。界面底部的listview的使用方法和之前类似,就不再详谈了。
7、现在要建立收藏的事件。和之前类似,依然使用一个bundle储存该食品的名称和位置。

  Intent intent1 = new Intent(Info.this,MainActivity.class);
              Bundle bundle1 = new Bundle();
              bundle1.putInt("position",tag);
              bundle1.putString("name",name[tag]);
              intent1.putExtras(bundle);

值得一提的是,在之前的主界面中需要添加onActivityResult函数,来处理返回的值,也就是将收藏的值添加进之前建的List < Map < String,String>> 收藏列表中去。

 protected void onActivityResult(int requestCode, int resultCode, Intent data1) {
        super.onActivityResult(requestCode, resultCode, data1);
        // RESULT_OK,判断另外一个activity已经结束数据输入功能,Standard activity result:
        // operation succeeded. 默认值是-1


        if (resultCode == 1) {
            if (requestCode == 1) {

                Bundle bundle=data1.getExtras();

                int tag = bundle.getInt("position");
                Map<String,String>temp = new LinkedHashMap<>();
              temp.put("icon",ID[tag]);
              temp.put("itemname",name[tag]);


                data.add(temp);
                 simpleAdapter.notifyDataSetChanged();


            }
        }
    }

8、星标的转换需要给该imagebutton加一个tag,再根据tag来setImageResource。

   Star.setOnClickListener((view) ->{
            int index=(Integer) view.getTag();
            if (index==0)
            {
                Star.setTag(1);
                Star.setImageResource(R.mipmap.full_star);
            }
            else
            {
                Star.setTag(0);
                Star.setImageResource(R.mipmap.empty_star);
            }




        });

9、点击长按事件需要设置onItemLongClick函数。在recycleview中需要删除数组元素,并且将绑定的arraylist中也删除掉。在listview中需要获取所点击的view,然后获取名称。

  LinearLayout layout = (LinearLayout)view;
               TextView status = (TextView) layout.findViewById(R.id.Name);
               String _name=status.getText().toString();

再通过判断位置来删除该收藏。
10、接下来还有悬浮窗的设计。添加依赖implementation

'com.android.support:design:27.1.1’设置布局文件
<android.support.design.widget.FloatingActionButton
android:id="@+id/btn"
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:src="@mipmap/colletions"
android:backgroundTint="@color/colorWhite"
android:backgroundTintMode=“src_atop”
app:layout_constraintBottom_toBottomOf=“parent”
app:layout_constraintRight_toRightOf=“parent”
android:layout_margin=“25dp” />

之后设置点击函数。判断两个view的可见状态,然后分别改变可视状态,并且改变悬浮窗图片。
11、添加RecyclerView动画。这里使用的默认动画。使用DefaultItemAnimator函数

DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator();
        defaultItemAnimator.setAddDuration(1000);
        defaultItemAnimator.setRemoveDuration(1000);
        recyclerView.setItemAnimator(defaultItemAnimator);

这里要注意的是,如果要采用默认动画,数据更新时不能使用Adapter.notifyDataSetChanged();而是要用Adapter.notifyItemChanged(int position)。

(3)实验遇到的困难以及解决思路

1、长按recycleview中控件删除时出现错误,提示数组超出范围。
解决思路:经过调试发现此时长按却进入了onclick函数,此时的positon为-1,数组name[position]自然不存在。经查阅后得知点击事件和长按点击事件是可以同时发生的。而此时可能处于一个两者之间的时间值。解决方法就是讲onLongClick中的返回参数改为true,使长点击事件成为一个独占事件。
2、recycleview一直无法导入依赖
解决思路:无法找到所对应版本的recycleview,因此直接从dependency中搜索相近版本的recycleview,加入进去。
3、布局不知道怎么使顶部占整体的三分之一
解决思路:令整个界面的weightSum为3,然后把顶部界面的RelativeLayout的layout_weight设为1.
4、传递页面时发现如果删除了一个列表项里的食品,则进入详情页面后与点击时的食品不匹配。
解决思路:删除食品时只是删除了adapter绑定的数据,并没有删除外部的字符数组的元素。应该将字符串的数组删除干净。
5、设置垂直居中时控件无法处在正确的位置
解决思路:因为垂直居中会使得控件处于整个父控件的中间,因为一开始我设置的整个中部空间为一个RelativeLayout,所以使得收藏夹按钮位于整个中间位置。经过修改后把收藏夹一行单独设为一个RelativeLayout,这样就可以垂直居中了。


四、实验思考及感想

1、这次实验主要涉及了页面之间的跳转和listview、recycleview的绑定。其中页面之间的跳转是安卓应用开发的重中之重,毕竟一个app不可能永远只有一个页面。页面跳转时需要注意传递的信息是否符合需要。还要注意在新的页面如何接收信息。recycleview等控件的绑定可以帮助我们更好地处理成批的信息,可以更方便之后的修改。
2、recycleview中自定义ViewHoler和adapter可以帮助我们实现许多新奇的效果。它具有低耦合高类聚的特性,过设置不同的LayoutManager,以及结合ItemDecoration , ItemAnimator,ItemTouchHelper,可以实现非常炫酷的效果。同时RecyclerView封装了viewholder的回收复用,也就是说RecyclerView标准化了ViewHolder,编写Adapter面向的是ViewHolder而不再是View了,复用的逻辑被封装了,写起来更加简单。直接省去了listview中convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。
3、我们再注入依赖时必须注意自己的版本号,如果版本号不匹配,将无法build,甚至于去掉该依赖后仍然会有报错。有时候需要重启一下as才行。如果实在不能匹配,可以考虑直接从project structure中的dependencies里添加依赖。
4、布局时要熟悉各种布局的形式与效果,尽量尝试每一种布局,这样到真正使用时可以根据需求更好地选择正确的布局方式。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值