自定义控件-下拉刷新



开发中最常用的下拉刷新控件

package com.pull.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

public class Pull2RefreshListView extends ListView {
 /**
  * 下拉刷新状态
  */
 public static final int PULL_REFRESH_STATE = 0x1;
 /**
  * 松开刷新状态
  */
 public static final int DISENTANGLE_REFRESH_STATE = 0x2;
 /**
  * 刷新状态
  */
 public static final int REFRESHING_STATE = 0x3;

 /**
  * 当前状态
  */
 private int mCurrentState = PULL_REFRESH_STATE;

 /**
  * 头布局
  */
 private View mHeaderView;
 /**
  * 箭头
  */
 private ImageView arrow;
 /**
  * 进度圆
  */
 private ProgressBar round;
 /**
  * 下拉刷新
  */
 private TextView pull;
 /**
  * 时间
  */
 private TextView date;
 /**
  * 布局高度
  */
 private int mHeight;
 /**
  * 按下时竖直方向的开始坐标
  */
 private int startY;
 /**
  * 向上旋转动画
  */
 private RotateAnimation animUp;
 /**
  * 向下旋转动画
  */
 private RotateAnimation animDown;

 public Pull2RefreshListView(Context context) {
  this(context, null);
 }

 public Pull2RefreshListView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }

 public Pull2RefreshListView(Context context, AttributeSet attrs,
   int defStyle) {
  super(context, attrs, defStyle);
  initHeaderView();
 }

 /**
  * 初始化头布局
  */
 private void initHeaderView() {
  mHeaderView = View.inflate(getContext(), R.layout.list_header, null);
  arrow = (ImageView) mHeaderView.findViewById(R.id.iv_arrow);
  round = (ProgressBar) mHeaderView.findViewById(R.id.pb_round);
  pull = (TextView) mHeaderView.findViewById(R.id.tv_pull);
  date = (TextView) mHeaderView.findViewById(R.id.tv_date);
  this.addHeaderView(mHeaderView);
  initData();
  initAnim();
 }

 /**
  * 初始化数据
  */
 private void initData() {
  mHeaderView.measure(0, 0);
  mHeight = mHeaderView.getMeasuredHeight();
  mHeaderView.setPadding(0, -mHeight, 0, 0);
 }

 /**
  * 滑动事件
  */
 @Override
 public boolean onTouchEvent(MotionEvent ev) {
  switch (ev.getAction()) {
  case MotionEvent.ACTION_DOWN:// 按下获取竖直方向的开始坐标
   startY = (int) ev.getY();

   break;
  case MotionEvent.ACTION_MOVE:// 移动获取竖直方西的差值
   if (startY == -1) {
    // 当用户按住头条新闻的viewpager进行下拉时,ACTION_DOWN可能被消费掉,
    // 导致startY没有赋值,此处需要重新获取一下
    startY = (int) ev.getY();
   }
   if (mCurrentState == REFRESHING_STATE) {
    // 如果是正在刷新, 跳出循环
    break;
   }

   int endY = (int) ev.getY();
   int dy = endY - startY;
   int firstVisiblePosition = getFirstVisiblePosition();// 当前显示的第一个item的位置

   int padding = -mHeight + dy;// 计算当前下拉控件的padding值
   if (padding > 20) {//限制下拉的距离
    padding = 20;
   }
   // 必须下拉,并且当前显示的是第一个item
   if (dy > 0 && firstVisiblePosition == 0) {
    mHeaderView.setPadding(0, padding, 0, 0);

    if (padding > 0 && mCurrentState != DISENTANGLE_REFRESH_STATE) {// 松开刷新,把当前状态改为松开刷新
     mCurrentState = DISENTANGLE_REFRESH_STATE;
     refreshState();
    } else if (padding < 0 && mCurrentState != PULL_REFRESH_STATE) {// 下拉刷新状态,把当前状态改为改为下拉刷新
     mCurrentState = PULL_REFRESH_STATE;
     refreshState();
    }

    return true;
   }
   break;
  case MotionEvent.ACTION_UP:// 抬起
   startY = -1;
   if (mCurrentState == DISENTANGLE_REFRESH_STATE) {
    mCurrentState = REFRESHING_STATE;
    refreshState();
    // 完整展示头布局
    mHeaderView.setPadding(0, 0, 0, 0);
    // 进行回调
    if (listener != null) {
     listener.onRefresh();
    }

   } else if (mCurrentState == PULL_REFRESH_STATE) {
    // 隐藏头布局
    mHeaderView.setPadding(0, -mHeight, 0, 0);
   }
   break;
  default:
   break;
  }
  return super.onTouchEvent(ev);
 }

 /**
  * 根据当前状态刷新界面
  */
 private void refreshState() {
  switch (mCurrentState) {
  case PULL_REFRESH_STATE:
   pull.setText("下拉刷新");
   round.setVisibility(View.INVISIBLE);
   arrow.setVisibility(View.VISIBLE);
   arrow.startAnimation(animDown);
   break;
  case DISENTANGLE_REFRESH_STATE:
   pull.setText("松开刷新");
   round.setVisibility(View.INVISIBLE);
   arrow.setVisibility(View.VISIBLE);
   arrow.startAnimation(animUp);
   break;
  case REFRESHING_STATE:
   pull.setText("正在刷新...");
   arrow.clearAnimation();// 清除箭头动画,否则无法隐藏
   round.setVisibility(View.VISIBLE);
   arrow.setVisibility(View.INVISIBLE);
   break;

  default:
   break;
  }
 }

 /**
  * 设置箭头动画
  */
 private void initAnim() {
  animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
    Animation.RELATIVE_TO_SELF, 0.5f);
  animUp.setDuration(200);
  animUp.setFillAfter(true);

  animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,
    0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  animDown.setDuration(200);
  animDown.setFillAfter(true);
 }

 /**
  * 下拉刷新的回调接口
  */
 public interface OnRefreshListener {
  /**
   * 刷新状态时调用
   */
  public void onRefresh();

  /**
   * 下拉加载更多
   */
  public void onLoadMore();
 }

 /**
  * 接口引用
  */
 private OnRefreshListener listener;

 /**
  * 暴露接口,设置监听
  */
 public void setOnRefreshListener(OnRefreshListener listener) {
  this.listener = listener;
 }

 /**
  * 刷新结束,隐藏头布局,还原状态
  */
 public void onRefreshComplete() {
  mHeaderView.setPadding(0, -mHeight, 0, 0);
  mCurrentState = PULL_REFRESH_STATE;
  pull.setText("下拉刷新");
  round.setVisibility(View.INVISIBLE);
  arrow.setVisibility(View.VISIBLE);

 }

}


头布局

<?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="wrap_content"
    android:orientation="horizontal" >

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="20dp" >

        <ImageView
            android:id="@+id/iv_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@drawable/common_listview_headview_red_arrow" />

        <ProgressBar
            android:id="@+id/pb_round"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="invisible"/>
    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/tv_pull"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:gravity="center"
            android:text="下拉刷新"
            android:textSize="20dp" />

        <TextView
            android:id="@+id/tv_date"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:gravity="center"
            android:text="2016-09-02 15-23-43"
            android:textSize="16dp" />
    </LinearLayout>

</LinearLayout>




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值