Android开发实现自定义水平滚动的容器示例

本文实例讲述了Android开发实现自定义水平滚动的容器。分享给大家供大家参考,具体如下:

public class HorizontalScrollView extends ViewGroup {
  //手势
  private GestureDetector mGestureDetector;
  private HorizontalScroller mScroller;
  private int curID;
  //快速滑动
  private boolean isFlying;
  //--回调函数-------------------------------------
  private OnChangeListener mListener;
  public void setOnChangeListener(OnChangeListener listener) {
    if (listener != null) {
      mListener = listener;
    }
  }
  public interface OnChangeListener{
    void move2dest(int curID);
  }
  public HorizontalScrollView(Context context) {
    this(context, null);
  }
  public HorizontalScrollView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }
  public HorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    mScroller = new HorizontalScroller();
    isFlying = false;
    initGesture(context);
  }
  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    // 模向移动,
    for (int i = 0; i < getChildCount(); i++) {
      View view = getChildAt(i);
      //给水平方向的每个view定位
      view.layout(i * getWidth(), 0, getWidth() + i * getWidth(), getHeight());
    }
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    for (int i = 0; i < getChildCount(); i++) {
      View view = getChildAt(i);
      view.measure(widthMeasureSpec, heightMeasureSpec);
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  }
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    mGestureDetector.onTouchEvent(event);
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
      if (!isFlying) {
        move2dest();
      }
      isFlying = false;
      break;
    case MotionEvent.ACTION_MOVE:
      break;
    case MotionEvent.ACTION_UP:
      break;
    default:
      break;
    }
    return true;
  }
  public void move2dest() {
    //
    int destID = (getScrollX() + getWidth() / 2) / getWidth();
    move2dest(destID);
  }
  public void move2dest(int destID) {
    curID = destID;
    if (destID > getChildCount() - 1) {
      destID = getChildCount() - 1;
    }
    if (mListener != null) {
      mListener.move2dest(curID);
    }
    int distance = (int) (destID * getWidth() - getScrollX());
    // scrollBy(distance, 0);
    mScroller.startScroll(getScrollX(), getScrollY(), distance, 0);
    invalidate();
  }
  /**
   * invalidate()此方法会触发下面的方法
   */
  @Override
  public void computeScroll() {
    // 如果存在偏移,就不断刷新
    if (mScroller.computeScrollOffset()) {
      scrollTo(mScroller.getCurrX(), 0);
      invalidate();
    }
    super.computeScroll();
  }
  private void initGesture(Context context) {
    mGestureDetector = new GestureDetector(context, new OnGestureListener() {
      @Override
      public boolean onSingleTapUp(MotionEvent e) {
        return false;
      }
      @Override
      public void onShowPress(MotionEvent e) {
      }
      @Override
      public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        scrollBy((int) distanceX, 0);
        return false;
      }
      @Override
      public void onLongPress(MotionEvent e) {
      }
      @Override
      /**
       * 快速滑动时
       */
      public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        isFlying = true;
        if (curID > 0 && velocityX > 0) {// 表示向左移
          move2dest(curID - 1);
        } else if (curID < getChildCount() && velocityX < 0) {
          move2dest(curID + 1);// 向右
        } else {
          move2dest();// 移到原位
        }
        return false;
      }
      @Override
      public boolean onDown(MotionEvent e) {
        return false;
      }
    });
  }
}
/**
 * 位移计算工具类
 *
 * @author chenlin
 *
 */
public class HorizontalScroller {
  private int startX;
  private int startY;
  private int distanceX;
  private int distanceY;
  private int currentX;
  private int currentY;
  private long startTime;
  private long duration = 1000L;
  private boolean isFinish;
  /**
   *
   * @param scrollX
   *      x坐标
   * @param scrollY
   *      y坐标
   * @param distanceX
   *      X方向移动的距离
   * @param distanceY
   *      y方向移动的距离
   */
  public void startScroll(int scrollX, int scrollY, int distanceX, int distanceY) {
    startX = scrollX;
    startY = scrollY;
    this.distanceX = distanceX;
    this.distanceY = distanceY;
    isFinish = false;
    startTime = SystemClock.uptimeMillis();
  }
  /**
   * 计算偏移量,
   *
   * @return true 还在移动 false:移动已经停止
   */
  public boolean computeScrollOffset() {
    if (isFinish) {
      return false;
    }
    long timePassed = SystemClock.uptimeMillis() - startTime;
    if (timePassed < duration) {
      currentX = (int) (startX + distanceX * timePassed / duration);
      currentY = (int) (startY + distanceY * timePassed / duration);
      System.out.println("currentX:::" + currentX);
    } else if (timePassed >= duration) {
      currentX = startX + distanceX;
      currentY = startY + distanceY;
      isFinish = true;
    }
    return true;
  }
  public int getCurrX() {
    return currentX;
  }
  public void setCurrentX(int currentX) {
    this.currentX = currentX;
  }
  public int getCurrentY() {
    return currentY;
  }
  public void setCurrentY(int currentY) {
    this.currentY = currentY;
  }
}

使用方法

public class ScrollActivity extends Activity implements OnCheckedChangeListener, OnChangeListener {
  private int[] ids = { R.drawable.a1, R.drawable.a2, R.drawable.a3, R.drawable.a4, R.drawable.a5, R.drawable.a6 };
  private HorizontalScrollView mView;
  private LinearLayout mLayout;
  private RadioGroup mGroup;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_myscrollview);
    init();
  }
  private void init() {
    mLayout = (LinearLayout) findViewById(R.id.body_layout);
    mGroup = (RadioGroup) findViewById(R.id.radiogroup);
    mView = new HorizontalScrollView(this);
    for (int i = 0; i < ids.length; i++) {
      ImageView imageView = new ImageView(this);
      imageView.setBackgroundResource(ids[i]);
      mView.addView(imageView);
    }
    mLayout.addView(mView);
    // 随便添加一个view
    View view = getLayoutInflater().inflate(R.layout.activity_progressview, null);
    mView.addView(view, 3);
    for (int i = 0; i < mView.getChildCount(); i++) {
      RadioButton radioButton = new RadioButton(this);
      // 设置id的编号
      radioButton.setId(i);
      mGroup.setOrientation(LinearLayout.HORIZONTAL);
      mGroup.addView(radioButton);
      if (i == 0) {
        radioButton.setChecked(true);
      }
    }
    mGroup.setOnCheckedChangeListener(this);
    mView.setOnChangeListener(this);
  }
  @Override
  public void onCheckedChanged(RadioGroup group, int checkedId) {
    mView.move2dest(checkedId);
  }
  @Override
  public void move2dest(int curID) {
    RadioButton radioButton = (RadioButton) mGroup.getChildAt(curID);
    radioButton.setChecked(true);
  }
}

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >
  <RadioGroup
    android:id="@+id/radiogroup"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
  </RadioGroup>
  <LinearLayout
    android:id="@+id/body_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
  </LinearLayout>
</LinearLayout>

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android基本组件用法总结》、《Android开发入门与进阶教程》、《Android布局layout技巧总结》、《Android视图View技巧总结》、《Android编程之activity操作技巧总结》、《Android资源操作技巧汇总》及《Android控件用法总结》

希望本文所述对大家Android程序设计有所帮助。

时间: 2017-10-17

Android使用Recyclerview实现图片水平自动循环滚动效果

简介: 本篇博客主要介绍的是如何使用RecyclerView实现图片水平方向自动循环(跑马灯效果) 效果图:  思路: 1.准备m张图片 1.使用Recyclerview实现,返回无数个(实际Interge.MAXVALUE)item,第n个item显示第n%m张图片 3.使用recyclerview.scrollBy  每个一段时间水平滚动一段距离 4.通过layoutManager.findFirstVisibleItemPosition()获取当前显示的第一个View是第几个item,上面

Android应用开发中自定义ViewGroup视图容器的教程

一.概述 在写代码之前,我必须得问几个问题: 1.ViewGroup的职责是啥? ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器的),我们的宽度(layout_width).高度(layout_height).对齐方式(layout_gravity)等:当然还有margin等:于是乎,ViewGroup的职能为:给childView计算出建议的宽和高和测量模式 :决定childView的位置:为什么只是

Android中实现多行、水平滚动的分页的Gridview实例源码

功能要求: (1)比如每页显示2X2,总共2XN,每个item显示图片+文字(点击有链接). 如果单行水平滚动,可以用Horizontalscrollview实现. 如果是多行水平滚动,则结合Gridview(一般是垂直滚动的)和Horizontalscrollview实现. (2)水平滚动翻页,下面有显示当前页的icon. 1.实现自定义的HorizontalScrollView(HorizontalScrollView.java): 因为要翻页时需要传当前页给调用者,所以fling函数中自己

详解Android使GridView横向水平滚动的实现方式

Android为我们提供了竖直方向的滚动控件GridView,但如果我们想让它水平滚动起来,就需要自己实现了. 以下使用的测试数据datas集合都为List<ResolveInfo>类型,用来存储手机中的所有App public static List<ResolveInfo> getAppData(Context context) { PackageManager packageManager = context.getPackageManager(); Intent mainI

Android自定义控件之继承ViewGroup创建新容器

欢迎大家来学习本节内容,前几节我们已经学习了其他几种自定义控件,分别是Andriod 自定义控件之音频条及 Andriod 自定义控件之创建可以复用的组合控件还没有学习的同学请先去学习下,因为本节将使用到上几节所讲述的内容. 在学习新内容之前,我们先来弄清楚两个问题: 1 . 什么是ViewGroup? ViewGroup是一种容器.它包含零个或以上的View及子View. 2 . ViewGroup有什么作用? ViewGroup内部可以用来存放多个View控件,并且根据自身的测量模式,来测量

android listview 水平滚动和垂直滚动的小例子

网上有很多解决 android listview 水平和垂直滚动的代码,我没有按照他们说的做(以前没搜到 O(∩_∩)O~) 我采用的是添加HorizontalScrollViewJava代码 复制代码 代码如下: < ScrollView android:id="@+id/ScrollView01" android:layout_height="300px" android:layout_x="16px" android:layout_y

从源码解析Android中View的容器ViewGroup

这回我们是深入到ViewGroup内部\,了解ViewGroup的工作,同时会阐述更多有关于View的相关知识.以便为以后能灵活的使用自定义空间打更近一步的基础.希望有志同道合的朋友一起来探讨,深入Android内部,深入理解Android. 一.ViewGroup是什么?        一个ViewGroup是一个可以包含子View的容器,是布局文件和View容器的基类.在这个类里定义了ViewGroup.LayoutParams类,这个类是布局参数的子类. 其实ViewGroup也就是Vie

Android自定义ViewGroup实现标签流容器FlowLayout

本篇文章讲的是Android 自定义ViewGroup之实现标签流式布局-FlowLayout,开发中我们会经常需要实现类似于热门标签等自动换行的流式布局的功能,网上也有很多这样的FlowLayout,但不影响我对其的学习.和往常一样,主要还是想总结一下自定义ViewGroup的开发过程以及一些需要注意的地方. 按照惯例,我们先来看看效果图 一.写代码之前,有几个是问题是我们先要弄清楚的: 1.什么是ViewGroup:从名字上来看,它可以被翻译为控件组,言外之意是ViewGroup内部包含了许

Android中标签容器控件的实例详解

前言 在一些APP中我们可以看到一些存放标签的容器控件,和我们平时使用的一些布局方式有些不同,它们一般都可以自动适应屏幕的宽度进行布局,根据对自定义控件的一些理解,今天写一个简单的标签容器控件,给大家参考学习. 下面这个是我在手机上截取的一个实例,是在MIUI8系统上截取的 这个是我实现的效果图 原理介绍 根据对整个控件的效果分析,大致可以将控件分别从以下这几个角度进行分析: 1.首先涉及到自定义的ViewGroup,因为现有的控件没法满足我们的布局效果,就涉及到要重写onMeasure和onL

Android使用RecyclerView实现水平滚动控件

前言 相信大家都知道Android滚动控件的实现方式有很多, 使用RecyclerView也比较简单. 做了一个简单的年龄滚动控件, 让我们来看看RecyclerView的使用方式, 主要有以下几点: (1) 对齐控件中心位置. (2) 计算滚动距离. (3) 高亮中心视图. (4) 实时显示中心数据. (5) 停止时自动对齐. (6) 滚动时, 设置按钮状态开关. 效果 1. 框架 主要关注RecyclerView部分逻辑. /** * 初始化年龄滑动条 */ private void ini

Android实现Activity水平和垂直滚动条的方法

本文实例讲述了Android实现Activity水平和垂直滚动条的方法.分享给大家供大家参考,具体如下: <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="

Android判断Activity是否在最上层的方法

本文实例讲述了Android判断Activity是否在最上层的方法.分享给大家供大家参考,具体如下: private boolean isTopActivity(Activity activity) { ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE); ComponentName cn = am.getRunningTasks(1).get(0).topActivity; return cn.get

Android检测Activity或者Service是否运行的方法

需求:假设我们的APP有3个页面AActivity,BActivity,CActivity,我们的APP需要一直运行在前台(特殊设备),要求实现一个监控服务,来监视APP是否运行,如果有3个页面都不运行了就说明这个APP已经挂掉了,否则说明APP在运行状态,不做处理,挂掉之后,我们需要重新启动App来让它继续处理运行状态,对外暴露一个来停止监控服务的广播,这样我们想停止监控服务时,发送一个广播即可. 思路:实现一个双进程的监控服务,服务中写一个定时器 Timer 来重复进行检测是否正在运行,如果

Android RecyclerView实现水平、垂直方向分割线

android RecyclerView不像过去的ListView那样随意的设置水平方向的分割线,如果要实现RecyclerView的水平/垂直分割线,则需要继承自RecyclerView.ItemDecoration重写getItemOffsets方法,从而增加水平/垂直分割线. 写一个例子. MainActivity.Java: package zhangphil.app; import android.content.Context; import android.graphics.Col

Android自定义水平或垂直虚线效果

项目中有时候会用到虚线,怎么办?drawable下创建一个shape类型的xml文件绘制,然后引用到view的background下?如果用到虚线的地方很多呢?创建多个,分别引用?横向的还好说,竖向的呢?垂直的虚线,普通的创建是显示不出来的,如果需要,就要进行旋转等的操作.但是,还是那个问题,需要很多个怎么办?挨个创建? 完全没必要,写个自定义,对外暴露设置虚线属性的方法就行.源码如下: 最后的说明很重要!!! 最后的说明很重要!!! 最后的说明很重要!!! 效果图: 源码: Imaginary

Android新建Activity的方法

本文实例讲述了Android新建Activity的方法.分享给大家供大家参考,具体如下: 在一个Android工程中,如何新建一个Activity?方法如下: 一.新建一个类(*.class),继承自android.app.Activity类. 二.在res/layout目录下新建一个布局xml文件,文件名随意(只能包含小写字母数字或下划线),用来设置新Activity的布局(对于如何设置Activity的布局,可参考本站相关内容). 三.打开AndroidManifest.xml文件,在里面进

Android中activity跳转按钮事件的四种写法

具体实现代码: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 方法1. 采用实现OnClickListener接口的类 ((Button) findViewById(R.i

Android仿微信朋友圈实现滚动条下拉反弹效果

微信朋友圈上面的图片封面,QQ空间说说上面的图片封面都有下拉反弹的效果,这些都是使用滚动条实现的.下拉,当松开时候,反弹至原来的位置.下拉时候能看到背景图片.那么这里简单介绍一下这种效果的实现. 1.效果图 这部手机显示的分辨率有限,很老的手机调试. 2.具有反弹效果BounceScrollView package com.org.scroll; import android.content.Context; import android.graphics.Rect; import androi

Android中Activity常用功能设置小结(包括全屏、横竖屏等)

本文实例讲述了Android中Activity常用功能设置小结(包括全屏.横竖屏等).分享给大家供大家参考,具体如下: Activity全屏设置 方式1:AndroidManifest.xml 复制代码 代码如下: <activity android:name="myAcitivty"  android:theme="@android:style/Theme.NoTitleBar.Fullscreen" /> 方式2:代码实现 复制代码 代码如下: re

Android实现Activity之间通信的方法

本文实例讲述了Android实现Activity之间通信的方法.分享给大家供大家参考.具体如下: 在一个Activity中可以使用系统提供的startActivity(Intent intent)方法打开新的Activity,在打开新的Activity前,你可以决定是否为新的Activity传递参数. 第一种:打开新的Activity,不传递参数 public class MainActivity extends Activity { @Override public void onCreate