[Android开发实战之仿微博下拉刷新菜单]


现在很多应用都增加了一个可以下拉刷新的控件适应移动端的触摸新交互方式,这边教程就来探讨一下如何实现这个功能。


                                                                                                                                                                                                                                                                                                                                                                       

微博的实际效果图。


首先我们很直观的发现,下拉刷新列表中的列表元素实际上是大体相同的。所以可以直接用listview来作为容器装载。

之后的问题在于,我们该如何实现下拉刷新的功能。

android的特点让我们有多种方式实现一个ui功能。

下面提供两种思路。

1、通过listview自带的headerview来实现。

2、通过一个view和listview集合实现。



1、通过inflate方法生成headerview,然后通过addheaderview方法给listview增加

通过ontouchevent判断当前header相对于父控件的位置来决定是否更新。

此外 还需要定义一个借口pulldownlistener 来给外部实现更新的具体操作。

下面是代码:


package com.example.test_weibo;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.text.Selection;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class TestListView extends ListView implements OnScrollListener{

	  /**
     * 头部的控件内容
     * 可根据header布局文件适当扩展
     */
	//头部的textview
	private TextView refresh_TextView;
	//头部的高度
	private int mHeader_Heght;
	//头部的view
    private View header_View;

  /*
   * 工具成员变量
   * 
   */
    
    //context 当前使用这个自定义的context
	private Context context;
	//inflate出实例的inflater
	private LayoutInflater inflater;
	
	/**
	 * 一些状态的常量值
	 * 另外可以 增加一些控件的属性值。如padding。
	 */
	private final int WHILE_REFRESH = 3;
	private final int REFRESH_FINISHED = 4;
	private final int PREPARE_REFRESH = 5;
	private final int WHILE_SCROLLING = 1;
	private final int SCROLLING_IDLE =  2;
	private final int GO_TO_REFRESH = 6;
	private final int FINISH_REFRESH = 7;
	
	/*
	 * 当前滚动的状态。 
	 */	
	private int mNowScroolState = SCROLL_STATE_IDLE;
	
	/**
	 *  当前的更新状态
	 */
	private int mNowRefreshState = PREPARE_REFRESH;
	
	/**
	 * 当前的adapter
	 */
	private ListAdapter adapter;
	//当前pulldownlistener
	private pullDownListener mPullDownListener;
	
	
	private Handler handler = new Handler(){
		@Override
		public void handleMessage(Message msg){
			
			switch (msg.what) {
			case GO_TO_REFRESH://更新操作
				setSelection(0);
				mNowRefreshState = WHILE_REFRESH;
				refresh_TextView.setText("更新中");
				//mPullDownListener.onRefresh(); 
 				/**
 				 * 做一个模拟的读取数据的过程实际上应该调pulldownlistener的onRefresh函数
 				 */
                new Thread(){
                	public void run(){
                		
                		try {
							Thread.sleep(2000);
							handler.sendEmptyMessage(FINISH_REFRESH);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
                	 	
                	}
                }.start();		
				
				break;
			case FINISH_REFRESH://结束更新时的ui操作。
				mNowRefreshState = PREPARE_REFRESH;
				reset_Header();
				//setSelection(1);
				break;
			default:
				break;
			}
			
		}
		
	};
	
    /**
     * 三个构造函数
     * @param context
     * @param attrs
     * @param defStyle
     */
	public TestListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
		init(context);
			// TODO Auto-generated constructor stub
		
		
	}
	
	
	public TestListView(Context context ,AttributeSet attrs) {
		// TODO Auto-generated constructor stub
	    super(context, attrs );
		   init(context);
			
			
	}
	
	public TestListView(Context context){
		super( context );
		
	}
	
	
	/**
	 * 初始化头部控件
	 * @param context
	 */
	
    public void init(Context context){
    	this.context = context; 
    	inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    	header_View = inflater.inflate(R.layout.header, this,false); 
    	refresh_TextView = (TextView)header_View.findViewById(R.id.header);
		addHeaderView(header_View);
		super.setOnScrollListener(this);
		measureView(header_View);
		mHeader_Heght = header_View.getMeasuredHeight();
		System.out.println("fucking_pad"+header_View.getPaddingTop());
		System.out.println("height"+header_View.getMeasuredHeight());
		
       this.setVerticalScrollBarEnabled(false);//设置垂直的滚动条不出现
    }
	
    
    @Override
    public boolean onTouchEvent(MotionEvent event){
    	
       switch (event.getAction()) {
	case MotionEvent.ACTION_DOWN://当手指按下的时候把滚动状态设置为滚动中 
		System.out.println("down");
		mNowScroolState = WHILE_SCROLLING;
		//Toast.makeText(context, "down", Toast.LENGTH_LONG).show();
		break;
	case MotionEvent.ACTION_MOVE://在移动的时候判断header的位置
		
		if(header_View.getBottom() > mHeader_Heght / 2 ){
			
			System.out.println("scroll_the_y"+event.getY());
			ready_For_Refresh();
		}
		
		if(header_View.getBottom() <= mHeader_Heght / 2 ){
			refresh_TextView.setText("下拉可更新");
		}
		
		System.out.println("header_height"+header_View.getHeight());
		System.out.println("header_top"+header_View.getTop());
		System.out.println("header_bottom"+header_View.getBottom());
		
		//Toast.makeText(context, "move", Toast.LENGTH_SHORT).show();
		setHeaderWhileFetching(event);
		break;
	case MotionEvent.ACTION_UP://手指抬起时将滚动状态设置为闲置。
		//判断是否从refresh
		//reset_Header();
		if(header_View.getBottom() > mHeader_Heght / 2){
			handler.sendEmptyMessage(GO_TO_REFRESH);
			
		}else{
			System.out.println("scroll_to_y"+mHeader_Heght);
			
			reset_Header();
		}
		mNowScroolState = SCROLL_STATE_IDLE;
		
		//Toast.makeText(context, "up", Toast.LENGTH_LONG).show();
		break;
	default://在其他情况将滚动状态为闲置状态。
		//判断是否refresh
		if(header_View.getBottom() < mHeader_Heght / 2){
			handler.sendEmptyMessage(GO_TO_REFRESH);
			//mNowRefreshState = WHILE_REFRESH;
		}else{
			System.out.println("scroll_to_y"+mHeader_Heght);
		    
	 
			
		    reset_Header();
		}
		
		mNowScroolState = SCROLL_STATE_IDLE;
		
		break;
	}
    	
		//回调原来的touchevent事件实现滚动
    	return super.onTouchEvent(event);
    }

    /**
     * 重置头部view
     */
    public void reset_Header(){
    	
    	mNowRefreshState = PREPARE_REFRESH;
    	refresh_TextView.setText("下拉更新");
    	setSelection(1);
    }
    /**
     * 调整textview的文字
     */
    public void ready_For_Refresh(){
    	refresh_TextView.setText("松开可更新");
    }
    
    /**
     * 没用的。。
     * @param event
     */
    public void setHeaderWhileFetching(MotionEvent event){
    	
    	int count = event.getHistorySize();
    	float old_Y;
    	for(int i = 0 ; i < count;++i){
    	   old_Y = event.getHistoricalY(i);
    	   System.out.println("old_Y"+old_Y);
    	}
    	float new_Y = event.getY();
    	
    	System.out.println( "new_Y  " + new_Y);
    	
    }
	/**
	 * 调用view的measure函数,计算出child的大小
	 * @param child
	 */
    private void measureView(View child) {
        ViewGroup.LayoutParams p = child.getLayoutParams();
        if (p == null) {
            p = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.FILL_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        
        int childWidthSpec = ViewGroup.getChildMeasureSpec(0,0 + 0, p.width);
        int lpHeight = p.height;
        System.out.println("fucking"+lpHeight);
        int childHeightSpec;
        if (lpHeight > 0) {  
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);   
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        child.measure(childWidthSpec, childHeightSpec);     
    }

    
    

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		// TODO Auto-generated method stub
		System.out.println("first"+firstVisibleItem + visibleItemCount);
	}


	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		// TODO Auto-generated method stub
		
	}
	/**
	 * 设置适配器,并把头部view隐藏
	 */
	@Override
	public void setAdapter(ListAdapter adapter){
		super.setAdapter(adapter);
		setSelection(1);
	    
	}
	/**
	 * this is the interface of listener to implement.
	 * you can change the function inside to adapt to your needs.
	 *
	 * @author wang
	 * 
	 */
	
	public interface pullDownListener{
		
		public void onRefresh();
		public void onMore();
		
	}
	
	/**
	 * 设置下拉菜单
	 * @param p
	 */
	public  void setOnPullDownListener(pullDownListener p){
		this.mPullDownListener = p;
	}
	

}



2、通过继承一个linearlayout来实现下拉列表的功能。

这个难度稍微大一点,但是从实际上来说也更贴近设计。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值