listview滑动到底部弹出按钮-button占用了listview的显示位置(尽力理解尽力解决)
来源:互联网 发布:mac系统 high sierra 编辑:程序博客网 时间:2024/06/10 10:15
今天在写一个程序。从接口获取数据解析后显示到自己的布局中:
先不说出现的问题先,总结一下这样一个程序的大体逻辑思路---->
大致步骤:
1:编写主布局(添加listview)
2:自定义listview的样式
:3:自定义适配器:BaseAdapter //这个过程可先伪造一些数据源进行调试,检查自己的程序
4:创建异步任务(AsyncTask)
o在doInBackground(该方法子线程执行)方法中执行网络访问的耗时操作(可使用httpurlconnection、okhttp)
o将得到的数据进行解析:可在doInBackground()也可在onPostExecute()方法中解析,并将解析的数据作为付给布局中数据源
5:使用适配器和数据源
问题:加载第一页listview时,设置在底部visiable状态为gone的按钮;占用了listview的位置:
效果图:
(存在问题:第一页加载时有空白,留意底部有一个空白占用着位置,但滑动之后空白消失)
解决后图片:
最后附上在底部弹出按钮的效果图:
上程序代码;
1:主布局的xml文件
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.administrator.qiubai10.MainActivity"> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="加载更多..." android:background="@color/colorAccent" android:id="@+id/btn_loadmore" android:layout_alignParentBottom="true" android:visibility="gone"/> <ListView android:layout_above="@id/btn_loadmore" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/listview"></ListView></RelativeLayout>
2:自定义listview的样式:(只有一个textview)
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textview_content"/></LinearLayout><--开发中使用相对布局的较多,因为在实现复杂界面时需要多层的嵌套,过度的渲染,而且在作修改时对其他的控件影响较大,但相对布局的控件等是较为独立的->
3:自定义适配器:
package com.example.administrator.qiubai10;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import java.util.List;/** * Created by Administrator on 2016/9/1. */public class Myadapter extends BaseAdapter { List<QiuBai> list ; Context context ; LayoutInflater inflater ; public Myadapter(List<QiuBai> list, Context context) { this.list = list; this.context = context; this.inflater = LayoutInflater.from(context); } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null ; if (convertView == null) { viewHolder = new ViewHolder(); convertView = inflater.inflate(R.layout.listview_item, parent, false); viewHolder.content = (TextView) convertView.findViewById(R.id.textview_content); convertView.setTag(viewHolder); }else{ viewHolder = (ViewHolder)convertView.getTag(); } if(position%2==0){ //这里是为了相邻两个textview不同的背景颜色 convertView.setBackgroundColor(context.getResources().getColor(R.color.colorHui)); }else{ convertView.setBackgroundColor(context.getResources().getColor(R.color.colorWhite)); } QiuBai qiuBai = list.get(position); viewHolder.content.setText(qiuBai.getContent()); return convertView; } class ViewHolder{ TextView content ; }}上面出现的 QiuBai 的类是我用来保存网络下载的数据对应的属性。后面我的数据源就是我的 QiuBai 对象的集合(QiuBai的代码在最后贴上)
4:主类(异步任务类为其内部类,方便访问主类的属性)
该类完成网络请求数据,对数据解析,初始化数据源,并且设置listview的适配器。
package com.example.administrator.qiubai10;import android.os.AsyncTask;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.AbsListView;import android.widget.Button;import android.widget.ListView;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity implements View.OnClickListener{ List<QiuBai> list = new ArrayList<QiuBai>(); private ListView listview; private Button btn_load; static int page =1; String path = "http://m2.qiushibaike.com/article/list/suggest?page=%s"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listview = ((ListView) findViewById(R.id.listview)); btn_load = ((Button) findViewById(R.id.btn_loadmore)); String url = String.format(path,String.valueOf(page)); new MyTask().execute(url); btn_load.setOnClickListener(this); } @Override public void onClick(View v) { if(v.getId()==R.id.btn_loadmore){ String url = String.format(path,String.valueOf(++page)); Log.d("bigname_log", "onClick: "+url); new MyTask().execute(url); } } //异步任务类:请求网络数据,解析后设置到list中 class MyTask extends AsyncTask<String, Void, List<QiuBai>> { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected List<QiuBai> doInBackground(String... params) { byte[] bytes = HttpUtils.getDatas(params[0]); String data = new String(bytes, 0, bytes.length); List<QiuBai> qiuBais = parseJson(data); list.addAll(qiuBais); return list; } @Override protected void onPostExecute(List<QiuBai> qiuBais) { Log.d("bigname_log", "onPostExecute: 加载适配器");//************************************************************** listview.setAdapter(new Myadapter(list, MainActivity.this)); listview.setOnScrollListener(new AbsListView.OnScrollListener() { /* * 1 abslistview view: * listview对象 * 2 int scrollstate: * listview的状态,有三种: * 0:停止 * 1:滑动 * 2:抛掷 * */ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { Log.d("bigname_log", "onScrollStateChanged: "+scrollState); } /* * abslistview view: listview对象 * int firstvisiableitem: 第一个可见item的位置 * int totalItemcount: 总的item个数(长度) * int visibleitemcount: 可见item的个数 * **/ @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { Log.d("bigname_log", "onScroll: 测量"); //***************************************** if ((firstVisibleItem + visibleItemCount) == totalItemCount) { Log.d("bigname_log", "onScroll: 等于总"); //******************************************** btn_load.setVisibility(View.VISIBLE); //此时的button悬浮在listview的上方,(覆盖)。应该是因为布局更新的问题。可调用listview的requestlayout()来重新加载 }else{ Log.d("bigname_log", "onScroll: 不等于总");//**************************************** btn_load.setVisibility(View.GONE); listview.requestLayout(); }<span style="white-space:pre"></span>//???????????????????????????????????? } }); // Log.d("bigname_log", "onPostExecute: ---加载适配器-----"); } }//写成静态方法,方便其他的类使用 private static List<QiuBai> parseJson(String data) {// 将每次访问的一页数据保存在page_list中,返回在添加到总的list中,这样在点击加载更多的时候之前的数据也还在 List<QiuBai> page_list = new ArrayList<QiuBai>(); try { JSONObject jo = new JSONObject(data); JSONArray items = jo.getJSONArray("items"); for (int i = 0; i < items.length(); i++) { JSONObject datas = items.getJSONObject(i); String id = datas.getString("id"); String content = datas.getString("content"); page_list.add(new QiuBai(content, id)); } } catch (JSONException e) { e.printStackTrace(); } return page_list; }}
如标题所说:listview滚动到达底部后,按钮弹出,但还是占了listview位置的问题。
请留意//******************************对应代码的位置。
setAdapter()在前,onScroll()在后,
这样的代码是不会出现这个问题的,但我之前是:onScroll()在前,setAdapter()在后。这样就出现了第一个页面button的位置占了listview的位置。活动一下才消失。
原因应该是listview绘制的问题。在第一次加载的时候不论你是否滑动了,他都会去调用一次onScroll()方法,如果此时的setAdapter()还没把数据设置好的话他就会预留这个位置。虽然我在activity_main.xml中已经把button设为gone了。
有一点我很不理解:为什么跟我onScroll()写的位置有关,不是我写哪里都可以,滑动一次被监听到才执行的吗?虽然结果确实有关,但却不知道为什么?
--》先说明一下什么时候才回去第一次调用onScroll方法:
度娘告诉我:
可是,我们会发现,当运行程序时,listview明明没有滚动,那为什么系统会调用onScroll方法呢?(补充:此时onScrollStateChanged并不会调用)
我们先看setOnScrollListener源码:
public void setOnScrollListener(OnScrollListener l) { //当你在设置监听的时候里面一般传一个匿名内部类,此时l就等于你那个匿名内部类,也就是说l已经不为空
mOnScrollListener = l; invokeOnItemScrollListener(); }setOnScrollListener里面调用了invokeOnItemScrollListener()方法,接着看该方法源码:
void invokeOnItemScrollListener() { if (mFastScroller != null) { mFastScroller.onScroll(mFirstPosition, getChildCount(), mItemCount); } if (mOnScrollListener != null) { mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);//这里调用onScroll,一切真相大白了。 } onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these. }
所以:!setScrollListener()的设置真的跟你设置的位置有关系的,现在终于弄懂了一点,也就是说,你在哪写的setOnscrollListener(),onScroll就会在哪开始执行一次。也就是说,你只要设置了,Scroll就会去执行。
好了接着继续分析:
下面来猜测一下:
程序先从onCreate()方法中进入布局,接着调用setContentView(R.layout.activity_main)这是后就是把布局加载到activity中去,但此时的listview 没有数据并且button也设置为gone,所以在此时的页面没东西显示的,然后执行了异步任务,下载数据。。。
到了onPostExecute()方法时(此时把数据都下载好,并解析存到数据源中):
按照如上的代码,把setAdapter()卸载setOnScrollListener()前面;打印的结果:
①
加载适配器
测量
不等于总
然后把setAdapter()移到//????????的那个位置也就是setAdapter()在setOnScrollListener()后面,打印结果
②
测量
等于总
加载适配器
测量
不等于
②时:
因为-等于总-所以会将button控件设为visiable可见,这时候就会占了底下的位置,也就是说button确实显示出来了(只是时间太短,你没感觉到),很快这时候再加载适配器把数据显示出来,这时候又调用了一次onscoll()方法,发现不等于,马上又把button设为gone了。此时数据已经加载到那里了,再调用requsetLayout()吧button去掉也没用了。(这里关键是button先设为visiable再变为gone这个过程引发的问题)
①时:也能够说的通:先加载适配器,把数据都显示到了listview中,再写setOnScrollListener()方法,此时判断为--不等于--所以button依然是gone的状态。。。
哈哈,到这就差不多完美结束这篇文章了。本来写这篇文章是想简单记录一下出现的这个问题和解决的办法,至于不理解也就算了,但写着写着就忍不住去弄懂背后的原因。本人还是小菜鸟,这篇文章肯定还存在很多漏洞,希望看到的能够指出来!
花了一晚上的时间,效率低,但挺开心的,毕竟好像是弄明白了这个东东。哈哈。。
</pre><p></p><div style="top: 3571px;"><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); font-family: Helvetica, Arial, sans-serif; line-height: 19.44px;">可是,我们会发现,当运行程序时,listview明明没有滚动,那为什么系统会调用onScroll方法呢?(补充:此时onScrollStateChanged并不会调用)</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); font-family: Helvetica, Arial, sans-serif; line-height: 19.44px;">我们先看setOnScrollListener源码:</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; color: rgb(51, 51, 51); font-family: Helvetica, Arial, sans-serif; line-height: 19.44px;"></p><pre class="java" style="margin-top: 0px; margin-bottom: 0px; padding: 0px; color: rgb(51, 51, 51); line-height: 19.44px;">public void setOnScrollListener(OnScrollListener l) { mOnScrollListener = l; invokeOnItemScrollListener(); }setOnScrollListener里面调用了invokeOnItemScrollListener()方法,接着看该方法源码:
void invokeOnItemScrollListener() { if (mFastScroller != null) { mFastScroller.onScroll(mFirstPosition, getChildCount(), mItemCount); } if (mOnScrollListener != null) { mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);//这里调用onScroll,一切真相大白了。 } onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these. }
- listview滑动到底部弹出按钮-button占用了listview的显示位置(尽力理解尽力解决)
- 尽力
- 尽力
- 从程序员到项目经理:你真的尽力了吗?
- ListView滑动到底部的监听
- ListView自动滑动到顶部(底部)的方法总结
- ListView自动滑动到顶部(底部)的方法总结
- 监听ListView滑动到底部
- Android 记录ListView滚动的位置的三种方法及判断是否滑动到底部
- 滑动到点击位置的ListView
- Android 解决ListView初始化时默认滑动到底部问题
- 你尽力了吗?(转)
- (转载)你尽力了吗
- 你尽力了么
- 你尽力了吗
- 你尽力了吗
- 你尽力了吗
- 你,尽力了吗?
- jsp的window对象的属性和方法大全
- java 两种日志的使用方式
- POJ 3414Pots
- android Spinner控件详解
- C语言求矩阵的行列式、伴随矩阵、逆矩阵
- listview滑动到底部弹出按钮-button占用了listview的显示位置(尽力理解尽力解决)
- yolo5类检测成功
- 面试题..
- Oracle学习笔记--- ORA-00911: invalid character 解决办法
- MATLAB去掉一组数据中的虚数
- 启动Spring:java编程方式
- 使用 poi 实现 excel 导出
- Java线程监听,意外退出线程后自动重启
- HDU 3746 Cyclic Nacklace