• 作用:Android系统中显示列表的控件 2.两种适配器 ArrayAdapter SimpleAdapter (1).数据适配器 作用:把复杂的数据(数组,链表,数据库,集合等)填充在指定视图界面上,是连接数据源和视图界面的桥梁。 (2)...

    1.理解ListView的基础使用

    (1).作用:Android系统中显示列表的控件

    2.两种适配器      ArrayAdapter     SimpleAdapter

    (1).数据适配器 作用:把复杂的数据(数组,链表,数据库,集合等)填充在指定视图界面上,是连接数据源和视图界面的桥梁。

    (2).ArrayAdapter(数组适配器):用于绑定格式单一的数据

               数据源:可以是集合或数组  

    (3).SimpleAdapter(简单适配器):用于绑定格式复杂的数据

               数据源:只能是特定泛型的集合

    (4).实现过程:新建适配器——>添加数据源到适配器——>视图加载适配器

    (5).数组适配器的实现

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ListView
            android:id="@+id/listView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>
    


    MainActivity.java

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    
    /**
     * 数组适配器
     */
    public class MainActivity extends AppCompatActivity { 
        private ListView listView; 
        private ArrayAdapter<String> arrayAdapter; 
        @Override protected void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            setContentView(R.layout.activity_main); 
            listView = (ListView) findViewById(R.id.listView); 
            //1.新建数据适配器 
            // ArrayAdapter(上下文,当前ListView加载的每一个列表项所对应的布局文件,数据源) 
            // 2.适配器加载数据源 
            String[] arrayData = {"苹果","香蕉","梨子","西瓜","桃子"};
            arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,arrayData); 
            //3.视图(ListView)加载适配器(arrayAdapter) 
            listView.setAdapter(arrayAdapter); 
        }
    } 

    
    

    (6).简单适配器的实现

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ListView
            android:id="@+id/listView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
            android:id="@+id/pic"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginLeft="10dp"
            android:src="@drawable/wolf"/>
    
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:textColor="#000000"
            android:text="狼人"/>
    
    </LinearLayout>

    MainActivity.java

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.AbsListView;
    import android.widget.AdapterView;
    import android.widget.ListView;
    import android.widget.SimpleAdapter;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 简单适配器
     */
    public class MainActivity extends AppCompatActivity{
    
        private ListView listView;
        private SimpleAdapter simpleAdapter;
        private List<Map<String,Object>> dataList;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listView = (ListView) findViewById(R.id.listView);
            //1.新建数据适配器
            /**
             * SimpleAdapter(context,data,resource,from,to)
             * context : 上下文
             * data : 数据源 List<? extends Map<String, ?>> data 一个Map所组成的List集合
             *        每一个Map都会去对应ListView列表中的一行
             *        每一个Map中的键都必须包含所有在from中所指定的键
             * resource :列表项布局文件的ID
             * from : Map中的键名
             * to : 绑定数据视图中的ID,与from成对应关系
             */
            //2.适配器加载数据源
            dataList = new ArrayList<Map<String, Object>>();
            simpleAdapter = new SimpleAdapter(this,getData(),R.layout.item,new String[]{"pic","test"},new int[]{R.id.pic,R.id.text});
            //3.视图(ListView)加载适配器(simpleAdapter)
            listView.setAdapter(simpleAdapter);
        }
    
        private List<Map<String,Object>> getData() {
            for (int i = 0; i < 20; i++) {
                Map<String,Object> map = new HashMap<String,Object>();
                map.put("pic",R.drawable.wolf);
                map.put("text","狼人"+i);
                dataList.add(map);
            }
            return dataList;
        }
    }
    

    3.两种监听器      OnItemClickListener     OnScrollListener    

    (1).监听器作用:android提供了很多种事件监听器,监听器主要是为了响应某个动作(动作的发起者可以是用户的操作也可以是android系统本身),我们可以通过监控这种动作行为,来完成我们需要的程序功能。监听器是程序和用户(或系统)交互的桥梁。                    

    (2).OnItemClickListener    可以处理视图中单个条目的点击事件

    (3).OnScrollListener    监测滚动的变化,可以用于视图在滚动中加载数据。

    (4).实现过程:视图直接设置监听器,在相关的实现方法中补充需要的代码即可。

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.AbsListView;
    import android.widget.AdapterView;
    import android.widget.ListView;
    import android.widget.SimpleAdapter;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 简单适配器
     */
    public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener,AbsListView.OnScrollListener{
    
        private ListView listView;
        private SimpleAdapter simpleAdapter;
        private List<Map<String,Object>> dataList;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listView = (ListView) findViewById(R.id.listView);
            //1.新建数据适配器
            /**
             * SimpleAdapter(context,data,resource,from,to)
             * context : 上下文
             * data : 数据源 List<? extends Map<String, ?>> data 一个Map所组成的List集合
             *        每一个Map都会去对应ListView列表中的一行
             *        每一个Map中的键都必须包含所有在from中所指定的键
             * resource :列表项布局文件的ID
             * from : Map中的键名
             * to : 绑定数据视图中的ID,与from成对应关系
             */
            //2.适配器加载数据源
            dataList = new ArrayList<Map<String, Object>>();
            simpleAdapter = new SimpleAdapter(this,getData(),R.layout.item,new String[]{"pic","test"},new int[]{R.id.pic,R.id.text});
            //3.视图(ListView)加载适配器(simpleAdapter)
            listView.setAdapter(simpleAdapter);
            listView.setOnItemClickListener(this);
            listView.setOnScrollListener(this);
        }
    
        private List<Map<String,Object>> getData() {
            for (int i = 0; i < 20; i++) {
                Map<String,Object> map = new HashMap<String,Object>();
                map.put("pic",R.drawable.wolf);
                map.put("text","狼人"+i);
                dataList.add(map);
            }
            return dataList;
        }
    
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            String text = listView.getItemAtPosition(position) + "";
            Toast.makeText(this,"position=" + position + "\ntext=" + text,Toast.LENGTH_SHORT).show();
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            switch (scrollState) {
                case SCROLL_STATE_FLING:
                    Log.i("Main","用户在手指离开屏幕之前,由于用力滑了一下,视图仍在滑动");
                    Map<String,Object> map = new HashMap<String,Object>();
                    map.put("pic",R.drawable.wolf);
                    map.put("text","增加项");
                    dataList.add(map);
                    simpleAdapter.notifyDataSetChanged();
                    break;
                case SCROLL_STATE_IDLE:
                    Log.i("Main","视图已经停止滑动");
                    break;
                case SCROLL_STATE_TOUCH_SCROLL:
                    Log.i("Main","手指没有离开屏幕,视图正在滑动");
                    break;
            }
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        }
    }
    

    4.适配器数据的刷新   notifyDataChanged


    展开全文
  • 使用拓展消息实现聊天界面和消息列表的头像和昵称的展示 上篇文章只是简单的介绍怎么集成环信,但是在自己的项目中涉及到聊天这一块。在做android开发的时候,往往要考虑到怎么展示用户昵称和头像的问题。说明一点:...

    使用拓展消息实现聊天界面和消息列表的头像和昵称的展示

    上篇文章只是简单的介绍怎么集成环信,但是在自己的项目中涉及到聊天这一块。在做android开发的时候,往往要考虑到怎么展示用户昵称和头像的问题。说明一点:我们这个项目的用户头像和昵称是我们后台返回给我们的。我们只需要给用户设置拓展属性。

    一、首先集成环信:

    app如何引入一个module作为依赖:

    1. 在自己的该app工作空间下,导入easeui这个module

    2. 在项目菜单的project structure中,app---dependencies--添加module依赖。

    3. clean工程—rebuild工程。


    首先要解决架包冲突问题。(v7冲突。)

    解决方案:1.app下的架包放到easeUIgradle中。

    2.实在不行,就查看所有gradle下面时候有重复的架包及依赖。


    二、集成环信的聊天界面:

    由于要使用到拓展消息,所以我们首先在工具类中定义一下我们自己和好友的属性。from表示我,to表示好友。

            public static final String FROM_AVATER="from_avater";
    	public static final String FROM_NICHENG="from_nicheng";
    	public static final String TO_AVATER="to_avater";
    	public static final String TO_NICHENG="to_nicheng";
    

    在easeui的widget包下的chatrow包的EaseChatRow这个类中,在消息的发送和接收处将其更改为拓展属性:

    /**
     * 聊天界面
     * 聊天界面需要获取用户的头像和昵称
     * 方法:采用扩展属性的方法。
     * 定义 自己和他人的属性:from_avater from_nicheng自己的头像和昵称   
     * to_avater  to_nicheng 对方的头像和昵称
     * 自身头像昵称在进入应用的时候存到文件中,待聊天界面直接从文件中取出来。
     * 对方头像从消息列表中获取
     */
    //环信中的聊天页面
    //set nickname and avatar
            /**
             * 聊天页面
             */
            if (message.direct() == Direct.SEND) {
                //  EaseUserUtils.setUserAvatar(context, EMClient.getInstance().getCurrentUser(), userAvatarView);
                try {
                    Glide.with(getContext()).load(message.getStringAttribute("from_avater")).into(userAvatarView);
                 //   usernickView.setText(message.getStringAttribute("from_nicheng"));
                    EaseUserUtils.setUserNick(message.getStringAttribute("from_nicheng"), usernickView);
                    
                } catch (HyphenateException e) {
    
                }
            }
            //   
            else {
                //  EaseUserUtils.setUserAvatar(context, message.getFrom(), userAvatarView);
                //  EaseUserUtils.setUserNick(message.getFrom(), usernickView);
                try {
                  //  usernickView.setText(message.getStringAttribute("from_nicheng"));
                   EaseUserUtils.setUserNick(message.getStringAttribute("from_nicheng"), usernickView);
                    Glide.with(getContext()).load(message.getStringAttribute("from_avater")).into(userAvatarView);
                } catch (HyphenateException e) {
    
                }
            }
    

    在自己的app下定义聊天界面ChatActivity如下:

    public class ChatActivity extends BaseActivity {
        private String logo;
        private static String name;
        private String logoPath;
        private String tradeName;
        public static ChatActivity activityInstance;
        private Bundle extras;
    
        //给扩展属性设置头像和昵称。
        EaseChatFragment.EaseChatFragmentHelper helper = new EaseChatFragment.EaseChatFragmentHelper() {
            @Override
            public void onSetMessageAttributes(EMMessage message) {
                // 附带扩展属性,头像和昵称他人的
                message.setAttribute(Utils.TO_AVATER, logo);
                message.setAttribute(Utils.TO_NICHENG, name);
              
                //我的头像  存到自己的文件中
                message.setAttribute(Utils.FROM_AVATER, logoPath);
                message.setAttribute(Utils.FROM_NICHENG, tradeName);
            }
            @Override
            public void onEnterToChatDetails() {
            }
            @Override
            public void onAvatarClick(String username) {
            }
            @Override
            public void onAvatarLongClick(String username) {
            }
            @Override
            public boolean onMessageBubbleClick(EMMessage message) {
                return false;
            }
            @Override
            public void onMessageBubbleLongClick(EMMessage message) {
            }
            @Override
            public boolean onExtendMenuItemClick(int itemId, View view) {
                return false;
            }
            @Override
            public EaseCustomChatRowProvider onSetCustomChatRowProvider() {
                return null;
            }
        };
        
        @Override
        protected void init() {
            super.init();
            //在布局中设置一个容器。集成环信的聊天界面添加进去
            setContentView(R.layout.activity_chat);
            initView();
        }
        private void initView() {
            //从消息列表获取头像和昵称
            logo = getIntent().getStringExtra(Utils.FROM_AVATER);
            name = getIntent().getStringExtra(Utils.FROM_NICHENG);
            //并从本地取出我的头像
            logoPath = SpUtils.getLogoPath(this);
            tradeName = SpUtils.getTradeName(this);
            //将环信的聊天界面chatFragment集成进来
            initHx();
        }
        public void initHx() {
            activityInstance = this;
            ChatFragment chatf = new ChatFragment();
            //获取从上个界面获取的参数,传给聊天界面。
            extras = getIntent().getExtras();
            chatf.setArguments(extras);
            //这个监听是接收到消息就给消息设置拓展属性。
            chatf.setChatFragmentListener(helper);
            getSupportFragmentManager().beginTransaction().add(R.id.container, chatf).commit();
    
        }
    
        /**
         * 继承环信的聊天页面  
         * 实现消息监听和聊天页面的标题上显示的对方昵称
         * 
         *
         */
        public static class ChatFragment extends EaseChatFragment implements EMMessageListener {
            /**
             * 设置聊天页面的title上面的昵称
             */
            @Override
            protected void setUpView() {
                super.setUpView();
                titleBar.setTitle(name);
                
            }
    
        }
    
    }
    

    当我们点击好友列表时(我的好友列表的数据是从服务器获取的。能够获取到好友的头像和昵称。自己的头像和昵称已进入自己的应用就保存到自己的文件中):

    //则点击进入聊天界面,和环信id

    //从服务器获取到昵称头像
                        String chatId = data.getChatId();
                        String name = data.getName();
                        String headerURL = data.getHeaderURL();


                        Log.i("shi",chatId+"#"+name+"#"+headerURL);
                        Intent intent = new Intent(this, ChatActivity.class);
                        Bundle bundle = new Bundle();
                        bundle.putString(EaseConstant.EXTRA_USER_ID, chatId);  //传递用户id
                        bundle.putInt(EaseConstant.EXTRA_CHAT_TYPE, EaseConstant.CHATTYPE_SINGLE); //传递是群聊还是单聊
                        intent.putExtras(bundle);
                        intent.putExtra(Utils.FROM_NICHENG, name);
                        intent.putExtra(Utils.FROM_AVATER, headerURL);
                        startActivity(intent);

    三、集成环信的消息列表:

    在easeui中找到EaseConversationAdapter这个类。当接收到最后一条消息的时候将其设置为对应的拓展属性。(这样在展示消息列表时会展示好友的头像昵称)

     else if(conversation.getType() == EMConversationType.ChatRoom){
                holder.avatar.setImageResource(R.drawable.ease_group_icon);
                EMChatRoom room = EMClient.getInstance().chatroomManager().getChatRoom(username);
                holder.name.setText(room != null && !TextUtils.isEmpty(room.getName()) ? room.getName() : username);
                holder.motioned.setVisibility(View.GONE);
            }else {/**
             * 获取列表最后一条消息是接收还是发送
             * 然后设置昵称和头像
             */
                EMMessage lastMessage = conversation.getLastMessage();
                if (lastMessage.direct() == EMMessage.Direct.RECEIVE) {
                    try {
                        Glide.with(getContext()).load(lastMessage.getStringAttribute("from_avater")).into(holder.avatar);
                        EaseUserUtils.setUserNick(lastMessage.getStringAttribute("from_nicheng"), holder.name);
                    } catch (HyphenateException e) {
                    }
                } else {
                    try {
                        EaseUserUtils.setUserNick(lastMessage.getStringAttribute("to_nicheng"), holder.name);
                        Glide.with(getContext()).load(lastMessage.getStringAttribute("to_avater")).into(holder.avatar);
                    } catch (HyphenateException e) {
                    }
                }
            }
            {
                // EaseUserUtils.setUserAvatar(getContext(), username, holder.avatar);
                // EaseUserUtils.setUserNick(username, holder.name);
                holder.motioned.setVisibility(View.GONE);
            }

    在app项目中集成环信的消息列表:

    1.	写一个布局文件,布局文件中设置一个容器,用来接收 环信的消息列表。
    EaseConversationListFragment  cf = new EaseConversationListFragment();
    getActivity().getSupportFragmentManager().beginTransaction().add(R.id.fl_contains,cf).commit();
    2.	给消息列表设置一个消息到来的监听。
    MClient.getInstance().chatManager().addMessageListener(emMessageListener);
    private EMMessageListener emMessageListener = new EMMessageListener() {
            @Override
            public void onMessageReceived(List<EMMessage> list) {
                //在环信包下的消息列表中对消息对象进行了筛选。将第0个消息存为32个8账号的消息,
                // 从消息列表中取出第0个消息对象。(第0个消息就是存有32个8该账号的消息对象)
                EMMessage emMessage = list.get(0);
                String s = emMessage.getBody().toString();
                try {
                    //这里是订单消息
                    EMConversation conversation = EMClient.getInstance().chatManager().getConversation("88888888888888888888888888888888");
                    //未读的消息数量普通消息
                    unreadMsgCount = conversation.getUnreadMsgCount();
                    Log.i("123---", s + "---from:" + emMessage.getFrom() + "---to:" + emMessage.getTo() + "---nicheng:" + emMessage.getStringAttribute("from_nicheng"));
                } catch (Exception e) {
                    cf.refresh();
                    Log.i("123---", s + "---from:" + emMessage.getFrom() + "---to:" + emMessage.getTo());
                }
                    cf.refresh();
            }
            //透传消息的
            @Override
            public void onCmdMessageReceived(List<EMMessage> list) {
                EMMessage emMessage = list.get(0);
                try{
                    EMCmdMessageBody body = (EMCmdMessageBody) emMessage.getBody();
                    String action = body.action();
                    if (action.equals("isDisable")){//启用和禁止 退出
                       //直接退出app和环信。
                        exitLogin();
                    }else if (action.equals("changePassword")){//修改密码  退出
                        exitLogin();
                    }else if (action.equals("setRights")){//权限   
                        EventBus.getDefault().post("修改权限");
                        //接收到修改权限的消息。立马去重新获取权限信息
                        reGetRight();
                    }else if (action.equals("reloadNickname")){//修改用户资料  刷新个人中心和首页
                        EventBus.getDefault().post("修改资料");
                        //刷新本页面
                        requestInfo();
                    }
                   
                }catch (Exception e){
                    
                }
                
            }
    
            @Override
            public void onMessageRead(List<EMMessage> list) {
    
            }
    
            @Override
            public void onMessageDelivered(List<EMMessage> list) {
    
            }
    
            @Override
            public void onMessageChanged(EMMessage emMessage, Object o) {
    
            }
        };
    

    给消息列表添加点击监听:

    3.给消息列表设置点击事件,点击跳到聊天界面。(先从好友列表聊天才会产生消息列表)
    cf.setConversationListItemClickListener(new EaseConversationListFragment.EaseConversationListItemClickListener() {
                @Override
                public void onListItemClicked(EMConversation conversation) {
                    // 聊天需要的bundle对象
                    Intent intent = new Intent(getActivity(), ChatActivity.class);
                    Bundle bundle = new Bundle();
                    bundle.putString(EaseConstant.EXTRA_USER_ID, conversation.getLastMessage().getUserName());
                    bundle.putInt(EaseConstant.EXTRA_CHAT_TYPE, EaseConstant.CHATTYPE_SINGLE);
                    intent.putExtras(bundle);
                    /**
                     * 从会话列表跳转到聊天页面
                     * 首先要判断最后一条信息是接收还是发送消息
                     * 然后分情况传递头像和昵称
                     *
                     */
                    EMMessage lastMessage = conversation.getLastMessage();
                    if (lastMessage.direct() == EMMessage.Direct.RECEIVE) {
                        try {
                            intent.putExtra(Utils.FROM_AVATER, lastMessage.getStringAttribute(Utils.FROM_AVATER));
                            intent.putExtra(Utils.FROM_NICHENG, lastMessage.getStringAttribute(Utils.FROM_NICHENG));
                        } catch (HyphenateException e) {
                            e.printStackTrace();
                        }
                    } else {
                        try {
                            intent.putExtra(Utils.FROM_AVATER, lastMessage.getStringAttribute(Utils.TO_AVATER));
                            intent.putExtra(Utils.FROM_NICHENG, lastMessage.getStringAttribute(Utils.TO_NICHENG));
                        } catch (HyphenateException e) {
                            e.printStackTrace();
                        }
                    }
                    startActivity(intent);
                }
            });


    activity销毁的时候记得移除消息的监听:

    EMClient.getInstance().chatManager().removeMessageListener(emMessageListener);  

    四、结束语

    大致集成步骤就是这样的,集成环信之前如果对环信一点都不了解建议先去环信上看一下文档。文章纯属按照自己的项目开发需求写的。大家可做参考。


     













    
    
    
    展开全文
  • Android仿QQ消息列表ListView滑动删除效果,具体详见:http://blog.csdn.net/top_code/article/details/19084879
  • 模仿微信消息列表的效果,ListView侧滑显示操作选项。
  • listview添加属性 android:stackFromBottom="true"//true 定位到底部 android:transcriptMode="alwaysScroll"//自动滚动定位到新增位置数据更新:list.addAll( list1);2.自下而上显示:...

    1.自上而下显示;

    listview添加属性

     android:stackFromBottom="true"//true 定位到底部
     android:transcriptMode="alwaysScroll"//自动滚动定位到新增位置

    数据更新:list.addAll( list1);

    2.自下而上显示:

    listview添加属性

     android:stackFromBottom="false"
     android:transcriptMode="normal"//

    数据更新:

     Collections.reverse(list1);//将新数据逆转、再添加到头部

    list.addAll( 0,list1);//在顶部添加数据





    展开全文
  • 本次实现目标是实现一个显示通知消息列表,最新消息显示在列表的最下面,并且列表默认滚动到最下面,列表是上拉不加载,下拉加载历史记录,手势操作类似聊天界面。 这里用到的是下面这三个类 implementation '...

    本次实现目标是实现一个显示通知消息列表,最新消息显示在列表的最下面,并且列表默认滚动到最下面,列表是上拉不加载,下拉加载历史记录,手势操作类似聊天界面。

    这里用到的是下面这三个类

    implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-21'
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.0.5.1'
    

    第一个类是实现下拉刷新、上拉加载更多的一个布局
    第二个类是一个滚动列表
    第三个类是加载、刷新的动画

    首先,在根布局下添加如下布局:

    <com.scwang.smartrefresh.layout.SmartRefreshLayout
            android:id="@+id/smartRefreshLayout"
            android:rotation="180"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <android.support.v7.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    
            </android.support.v7.widget.RecyclerView>
            <com.scwang.smartrefresh.layout.footer.ClassicsFooter
                android:rotation="180"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
        </com.scwang.smartrefresh.layout.SmartRefreshLayout>
    
    

    这里最重要的是 rotation 旋转属性,将SmartRefreshLayout布局旋转180后,RecyclerView与ClassicsFooter也是倒转的,不过没关系,这正是我们想要的,主要是为了让ClassicsFooter这个 “加载更多” 的动画出现在RecyclerView的上方,替换原先的 “下拉刷新” 动画,这样 “加载更多” 动画消失后,界面不会回弹。

    正常状态下,下拉刷新动画位于RecyclerView的上方,刷新完成后,动画消失会回弹,加载更多动画不会。

    那这样写,总不能让用户倒转手机看吧?我是干这种蠢事的人吗?

    解决办法是把 ClassicsFooter 也旋转180度,那么他的 位置不变,内容变回正常,同样的,RecyclerView里面的 item布局 也旋转180度,那么一切不是看起来很正常了?

    那么还有个问题,默认滚动 到底部怎么解决?要使用RecyclerView的滚动方法滚过去吗?不不不,要明白,界面上看到的列表最后一个item其实就是列表的第一个item,数据初始化的时候,就默认滚动到第一个位置的。

    看到这里也许你应该明白怎么写了,不过要注意的是 SmartRefreshLayout的layout_height属性一定要设置为wrap_content,不然,当RecyclerView里面的数据不足以滚动的时候,会有一段 空白距离

    展开全文
  • 今天想和大家分享的是手机QQ消息列表侧滑删除效果,这种效果在IOS中被封装为一个列表控件,而手机QQ则是将这个功能移植到了Android上,换言之,这并非是手机QQ的独创。尽管如此,用户体验依然得到了很大的提升。那么...

              今天想和大家分享的是手机QQ消息列表侧滑删除效果,这种效果在IOS中被封装为一个列表控件,而手机QQ则是将这个功能移植到了Android上,换言之,这并非是手机QQ的独创。尽管如此,用户体验依然得到了很大的提升。那么,今天就让我们一起来学习实现这个效果吧。


              一、实现原理

             给每个ListView的项目中添加一个按钮,这个按钮在默认情况下是隐藏的,当用户接触屏幕后,在OnTouch事件里捕捉用户的行为,按照一定的规则来决定是显示还是隐藏按钮,而当按钮处于显示状态时,我们单击该按钮即可实现对该按钮所在项目的删除。这里我们以手指按下和抬起的横坐标作为判断用户是否滑动手指的标准,当两点间距离的绝对值>25时,即认为用户的手指滑动了,在此条件下,决定隐藏按钮还是显示按钮。


             二、基本思路

          ListView中每一项的内容是由BaseAdapter中的getView()方法来决定的,因此我们需要根据用户的行为来返回相应的View,所以我们要在适配器中获取列表项中的每一个项目,并对该项目添加OnTouch事件的注册,来决定是否显示这个按钮,而在显示按钮的情况下,我们需要获取这个按钮,并对这个按钮添加OnClick事件的注册,因此基本的思路就是:

              1、获取列表中的每一项,为其添加OnTouchListener(),实现OnTouch方法,在OnTouch方法里捕捉用户行为,并做出响应

              2、对于显示按钮的项目,为其添加OnClickListener(),实现OnClick方法,在OnClick方法里相应用户的点击,notifyDataSetChanged()使用更新列表


              三、具体实现

    /*
      仿 QQ消息滑动删除效果
      作者:秦元培
      时间:2013年12月26日
      这个程序对于手势的识别还不是很好,基本上可以满足要求,但是还需要完善这一部分,例如解决同时点击的问题
    */
    package com.Android.SliderToRemove;
    
    import java.util.List;
    import java.util.Map;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.view.animation.AlphaAnimation;
    import android.view.animation.Animation;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    public class ListViewAdapter extends BaseAdapter {
    	public List<Map<String, Object>> mData;
    	private Context mContext;
    	private float mDownX,mUpX;
    	private Button BtnDelete;
    	private boolean IsShowButton;
    
    	public ListViewAdapter(Context context,List<Map<String,Object>> data) 
    	{
    		this.mData = data;
    		this.mContext = context;
    	}
    
    	@Override
    	public int getCount() 
    	{
    		return mData.size();
    	}
    
    	@Override
    	public Object getItem(int Index) 
    	{
    		return mData.get(Index);
    	}
    
    	@Override
    	public long getItemId(int Index) 
    	{
    		return Index;
    	}
    
    	@Override
    	public View getView(final int mPosition, View mConvertView, ViewGroup parent) 
    	{
    		ViewHolder mHolder = null;
    		if (mConvertView == null) 
    		{
    			mConvertView = LayoutInflater.from(mContext).inflate(R.layout.layout_item,null);
    			mHolder = new ViewHolder();
    			//Header
    			mHolder.Header= (ImageView)mConvertView.findViewById(R.id.Image);
    			//Content
    			mHolder.Content= (TextView)mConvertView.findViewById(R.id.Content);
    			//Delete
    			mHolder.Delete=(Button)mConvertView.findViewById(R.id.Delete);
    			mConvertView.setTag(mHolder);
    		} else 
    		{
    			mHolder = (ViewHolder) mConvertView.getTag();
    		}
    		//列表项Touch事件绑定
    		mConvertView.setOnTouchListener(mTouchListener);
    		//列表项中删除按钮的Click事件绑定
    		mHolder.Delete.setOnClickListener(new OnClickListener() 
    		{ 
    			 @Override
    			 public void onClick(View v) 
    			 {
    
    				if (BtnDelete != null) {
    					BtnDelete.setVisibility(View.GONE); // 点击删除按钮后,影藏按钮
    					mData.remove(mPosition); // 把数据源里面相应数据删除
    					notifyDataSetChanged(); // 删除数据,加动画
    				  }
    			  }
    		});
    		//Fuck!这里必须要先进行手势的处理,然后再绑定要显示的内容,否则会出现意外!!!!!
    		mHolder.Header.setBackgroundResource((Integer) mData.get(mPosition).get("Header"));
    		mHolder.Content.setText((CharSequence) mData.get(mPosition).get("Content"));
    		return mConvertView;
    	}
    
    	OnTouchListener mTouchListener=new OnTouchListener()
    	{
    		@Override
    		public boolean onTouch(View mView, MotionEvent mEvent) 
    		{
    			final ViewHolder holder = (ViewHolder)mView.getTag();
    			BtnDelete=holder.Delete;
    			switch (mEvent.getAction()) 
    			{
    			  case MotionEvent.ACTION_DOWN: 
    				  mDownX = mEvent.getX(); 
    				  
    				  if(BtnDelete!=null)
    				  {
    					  //如果手指按下和抬起的水平距离的绝对值>25,则认为发生了滑动
    					  if (Math.abs(mDownX - mUpX) > 25) { 
    						  //如果当前按钮是显示,则隐藏,反之,则显示
    							if(IsShowButton)
    							{
    							   //隐藏按钮的渐变动画
    							   HideAnimation(holder.Delete);
    							   holder.Delete.setVisibility(View.GONE);
    							   IsShowButton=false;
    							}
    							else
    							{
    								//显示按钮的渐变动画
    								ShowAnimation(holder.Delete);
    								holder.Delete.setVisibility(View.VISIBLE);
    								IsShowButton=true;
    							}
    							//获取当前项目中的删除按钮,便于执行下一步
    							BtnDelete = holder.Delete; 
    					  }
    				  }
    				break;
    			  case MotionEvent.ACTION_UP: 
    				  mUpX = mEvent.getX(); 
    				break;
    			}
    			return true;
    		}
    	};
    
    	//显示按钮的渐变动画
    	public void ShowAnimation(View v)
    	{
            Animation Ani_Alpha = new AlphaAnimation(0.1f, 1.0f);
    		Ani_Alpha.setDuration(1000);
    		v.setAnimation(Ani_Alpha);
    	
    	}
    	//隐藏按钮的渐变动画
    	public void HideAnimation(View v)
    	{
    		Animation Ani_Alpha = new AlphaAnimation(1.0f, 0.1f);
    		Ani_Alpha.setDuration(1000);
    		v.setAnimation(Ani_Alpha);
    	}
    	
    	
    	static class ViewHolder 
    	{
    		ImageView Header;
    		TextView Content; 
    		Button Delete; 
    	}
    
    }
    

             四、最终效果


              

    展开全文
  • Android学QQ聊天列表展示ListView稍微修改下实现的,比完全copy感觉爽多了布局文件:activity_main.xml<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=...
  • Android 实现聊天列表

    2017-05-27 23:00:18
    本文涉及的聊天列表为之前做的一个拼单App的一个功能,完整项目地址 效果图如下: 1. 依赖 实时通讯框架采用 环信即时通讯云 右侧未读消息气泡使用开源库 Android 徽章控件 左划删除消息使用开源库 ...
  • 在上一篇文章《Android应用程序消息处理机制(Looper、Handler)分析》中,我们分析了Android应用程序的消息处理机制,本文将结合这种消息处理机制来详细分析Android应用程序是如何获得键盘按键消息的。
  • 我们知道,Android应用程序是通过消息来驱动的,即在应用程序的主线程(UI线程)中有一个消息循环,负责处理消息队列中的消息。我们也知道,Android应用程序是支持多线程的,即可以创建子线程来执行一些计算型的任务...
  • 1. 为什么需要Android消息机制 Android规定访问UI只能在主线程中进行。若在子线程中访问UI就会抛出异常。这个验证由ViewRootImpl的checkThread()来完成。 为什么不允许在非主线程访问UI呢?这是因为Android的UI...
  • 通许软件的聊天窗口。此Demo 高仿微信聊天界面
  • android仿微信好友列表

    2018-04-12 11:04:33
    android studio实现微信好友列表功能,注意有一个jar包我没有放上来,请大家到MainActivity中的那个网址里面下载即可,然后把pinyin4j-2.5.0.jar复制粘贴到项目的app/libs文件夹里面,然后clean项目就可以使用了实现...
  • ListView这个列表控件在Android中是最常用的控件之一,几乎在所有的应用程序中都会使用到它。 目前正在做的一个记账本APP中就用到了它,主要是用它来呈现收支明细,是一个图文列表的呈现方式,下面就讲讲具体是...
  • 之前集成即时通讯(环信)的时候,需要用到自定义消息的功能。而在开发过程中遇到了许多的问题,之前工作比较忙,现在有时间了记录一下。 首先,在聊天界面添加一个发送扩展消息的MenuItem: 在ChatFragment类中定义...
  • 一、内容 设计两种形式的对话框程序,一种是发出提示信息的普通对话框,另一种是用户登录对话框。 二、实现 1.主界面 activity_main....LinearLayout xmlns:android="http://schemas.android.com/apk/res/androi...
  • 学习和二次开发的利器(作者持续更新)   先上干货,项目的体验安装包地址:  http://www.imgeek.org/data/download/Fanxin.apk  整个项目的源码包将近40M(素材太杂,未清理)太大上传不了,源码可点击... ...  
  • android列表xml模板

    2014-06-16 10:01:23
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" >
1 2 3 4 5 ... 20
收藏数 55,732
精华内容 22,292