欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android仿京东首页画轴效果

程序员文章站 2024-02-26 12:44:46
记得之前京东首页有一个效果,有一个画轴,然后可以滚动画轴,去打开画(不知道怎么去形容这个效果,就叫做画轴效果吧- -!),然后去做相关操作,刚开始看到这个效果,想法是动态的...

记得之前京东首页有一个效果,有一个画轴,然后可以滚动画轴,去打开画(不知道怎么去形容这个效果,就叫做画轴效果吧- -!),然后去做相关操作,刚开始看到这个效果,想法是动态的去改变一个imageview的高度,基本效果也就出来了,不过滚动部分的内容,当时接触的也不是很多,只是看过一些大牛的博客,略微了解了一点,当时也忙着写项目,也就没去多想,前些天忽然想到这个效果,就想着实现一下,不过京东新版本好像去掉这个东西了,只能凭着自己的记忆来大概搞一下,也是对滑动这部分内容的一个小练习吧.

先看一下效果图:

Android仿京东首页画轴效果

一、需求分析

看到效果之后,先来分析一下:
首先是需要一个可以滑动的画轴,并且这个画轴需要一定的滑动空间,有滑动的效果,这个用scroller帮助完成就可以了.
然后看一下画轴点击移动时候的背景图,是跟随画轴移动,动态改变高度的.这个用一个imageview来搞定,设置imageview的scaletype就可以了,不过这个地方有一些小问题,下面会说.

二、具体实现

简单分析完,来实现一下,先来做一下画轴.创建一个scrollpaintview继承自relativelayout,因为需要一定的滑动空间,所以需要是一个viewgroup.

scrollpaintview的一些基本属性:

public class scrollpaintview extends relativelayout {
 /**
 * tag
 */
 private static final string tag = "scrollpaintview";
 /**
 * 默认滚轴高度
 */
 private final int default_paint_scroll_height = 25;
 /**
 * 默认滚动的速度
 */
 private final int default_scroll_speed = 1000;
 /**
 * 默认分割点高度
 */
 private final int default_partition_node = 150;
 /**
 * 默认画轴文字大小
 */
 private final int default_paint_scroll_txt_size = 16;
 /**
 * scroller
 */
 private scroller mscroller;
 /**
 * 滚轴iv
 */
 private imageview mpaintscrollimageview;
 /**
 * 滚轴tv
 */
 private textview mpaintscrolltextview;
 /**
 * 图画iv
 */
 private imageview mpaintview;
 /**
 * 画轴图
 */
 private bitmap mpaintscrollbp;
 /**
 * 画轴高度
 */
 private int mpaintivheight;
 /**
 * 画轴文字
 */
 private string mpaintscrolltxt;
 /**
 * 画轴文字大小
 */
 private float mpaintscrolltxtsize;
 /**
 * 画轴文字颜色
 */
 private int mpaintscrolltxtcolor;
 /**
 * 图画开始时的高度
 */
 private int mpaintstartheight;
 /**
 * 上一次获取的y
 */
 private int mlasty;
 /**
 * 滚动速度
 */
 private int mscrollspeed;
 /**
 * 分隔节点
 */
 private int partitionnode;
 /**
 * 是否是向上滚动
 */
 private boolean isscrllertop = false;
 /**
 * 是否正在点击
 */
 private boolean isclick = false;
 /**
 * 布局参数
 */
 private layoutparams lpp;
 /**
 * 屏幕高度
 */
 private int screenheight;
 /**
 * 屏幕宽度
 */
 private int screenwidth;
 /**
 * 回调监听
 */
 private scrollpaintcompletelistener listener;
 /**
 * 上一次滚动的y值
 */
 private int lastscrolly;

 /**
 * 构造方法
 */
 public scrollpaintview(context context, attributeset attrs, int defstyleattr) {
 super(context, attrs, defstyleattr);
 // 获取属性
 typedarray ta = context.obtainstyledattributes(attrs, r.styleable.scrollpaintview);
 mpaintivheight = (int) ta.getdimension(r.styleable.scrollpaintview_paintscrollheight, typedvalue.applydimension(
  typedvalue.complex_unit_dip, default_paint_scroll_height, getresources().getdisplaymetrics()));
 mscrollspeed = ta.getinteger(r.styleable.scrollpaintview_scrollspeed, default_scroll_speed);
 partitionnode = ta.getinteger(r.styleable.scrollpaintview_scrollpartitionnode, default_partition_node);
 mpaintscrollbp = drawabletobitamp(ta.getdrawable(r.styleable.scrollpaintview_paintscrollsrc));
 mpaintscrolltxt = ta.getstring(r.styleable.scrollpaintview_paintscrolltxt);
 mpaintscrolltxtcolor = ta.getcolor(r.styleable.scrollpaintview_paintscrolltxtcolor, color.black);
 mpaintscrolltxtsize = px2sp(ta.getdimensionpixelsize(r.styleable.scrollpaintview_paintscrolltxtsize, default_paint_scroll_txt_size));
 ta.recycle();
 }
}

看一下创建画轴:

 /**
 * 创建滚轴
 */
 private void makepaintscroll() {
 // 如果已经存在,则不再创建
 if (null != mpaintscrollimageview || null != mpaintscrolltextview) {
  return;
 }
 // 创建滚轴
 mpaintscrollimageview = new imageview(getcontext());
 layoutparams lp = new layoutparams(layoutparams.match_parent, layoutparams.match_parent);
 lp.height = mpaintivheight;
 mpaintscrollimageview.setlayoutparams(lp);
 mpaintscrollimageview.setscaletype(imageview.scaletype.fit_xy);
 mpaintscrollimageview.setimagebitmap(null == mpaintscrollbp ? makedefaultscroll() : mpaintscrollbp);
 addview(mpaintscrollimageview);
 // 创建文字
 mpaintscrolltextview = new textview(getcontext());
 layoutparams lpt = new layoutparams(layoutparams.match_parent, layoutparams.match_parent);
 lpt.height = mpaintivheight;
 mpaintscrolltextview.setlayoutparams(lpt);
 mpaintscrolltextview.settext(null == mpaintscrolltxt ? "" : mpaintscrolltxt);
 mpaintscrolltextview.settextsize(mpaintscrolltxtsize);
 mpaintscrolltextview.settextcolor(mpaintscrolltxtcolor);
 mpaintscrolltextview.setgravity(gravity.center);
 addview(mpaintscrolltextview);
 }

 /**
 * 设置默认的滚轴
 *
 * @return
 */
 private bitmap makedefaultscroll() {
 bitmap defaultbp = bitmap.createbitmap(screenwidth, mpaintivheight,
  bitmap.config.argb_8888);
 //填充颜色
 defaultbp.erasecolor(color.parsecolor("#ff0000"));
 return defaultbp;

 }

创建了一个画轴imageview和一个文字textview作为初始的画轴,如果没有传入画轴的图片,则默认去创建一个画轴.不难理解,接着去配合scroller,让画轴滚动起来.

简单滚动:

 /**
 * 处理view
 */
 private void handleview() {
 // 初始化scroller
 mscroller = new scroller(getcontext());
 // 画轴点击效果
 mpaintscrollimageview.setontouchlistener(new ontouchlistener() {
  @override
  public boolean ontouch(view view, motionevent event) {
  int x = (int) event.getrawx();
  int y = (int) event.getrawy();
  int action = event.getaction();
  switch (action) {
   case motionevent.action_down: 
   isclick = true;
   mlasty = y;
   if (!mscroller.isfinished()) { // 如果上次的调用没有执行完就取消。
    mscroller.abortanimation();
   }
   return true;
   case motionevent.action_move: 
   // 移动的距离
   int dy = y - mlasty;
   mlasty = y;
   // 滑动
   scrollby(0, -dy);
   return true;
   case motionevent.action_up:
   mscroller.startscroll(getscrollx(), getscrolly(), -getscrollx(), -getscrolly(), 1000);
   invalidate();
   return true;
  }
  return false;
  }
 });
 }

 /**
 * 滑动处理
 */
 @override
 public void computescroll() {
 if (mscroller.computescrolloffset()) { // 计算新位置,并判断上一个滚动是否完成。 
  scrollto(mscroller.getcurrx(), mscroller.getcurry());
  invalidate();
  }
 }

这样滑动处理就做完了,在布局中引用一下,看一下效果

activity_main:

 <?xml version="1.0" encoding="utf-8"?>
<relativelayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="#eeeeee"
 tools:context="com.example.junweiliu.scrollpaintdemo.mainactivity">
  <!--画轴控件-->
 <com.example.junweiliu.scrollpaintdemo.widget.scrollpaintview
  android:id="@+id/spv_paint"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:paintscrollheight="25dp"
  app:paintscrollsrc="@mipmap/paint_scroll_img"
  app:paintscrolltxt="拉我看看"
  app:paintscrolltxtcolor="#ff000000"
  app:paintscrolltxtsize="16sp"
 >
 </com.example.junweiliu.scrollpaintdemo.widget.scrollpaintview>
</relativelayout>

效果图:

Android仿京东首页画轴效果

滚动条基本能用了,接着来设置一个imageview来配合使用下,先获取到一个imageview,然后拖动画轴时,来动态改变imageview的高度,在做这部分内容前,先来考虑下,因为需求需要的是图画整体不会变形,是一点一点拉开的感觉,就像是打开一幅画一样,那么用哪种scaletype能满足呢.试了好多种,来分别看一下:

相关代码:

提供一个设置imageview的方法
在motionevent.action_move:中动态改变imageview的高度
滑动时动态改变imageview的高度

 /**
 * 设置paintview
 *
 * @param paintview
 */
 public void setpaintview(imageview paintview) {
 if (null == paintview) {
  log.e(tag, "设置的view为空");
  return;
 }
 mpaintview = paintview;
 }

motionevent.action_move:

 // 滑动处理 
 case motionevent.action_move: 
 ...
 // 动态改变高度
 if (math.abs(getscrolly()) > 0) {
    lpp.height = mpaintstartheight + math.abs(getscrolly());
    mpaintview.setlayoutparams(lpp);
   }

滑动处理:

 /**
 * 滑动处理
 */
 @override
 public void computescroll() {
 if (mscroller.computescrolloffset()) { // 计算新位置,并判断上一个滚动是否完成。
  // 请求处理点击事件,防止父控件滑动
  requestdisallowintercepttouchevent(true);
  scrollto(mscroller.getcurrx(), mscroller.getcurry());
  // 重新设置显示的控件高度
  if (0 < math.abs(mscroller.getcurry())) {
  if (!isscrllertop) {
   lpp.height = mpaintstartheight + math.abs(mscroller.getcurry()) + mpaintivheight / 2;
  } else {
   lpp.height = mpaintstartheight + math.abs(mscroller.getcurry()) - mpaintivheight / 2;
  }
  } else {
  lpp.height = mpaintstartheight;
  }
  mpaintview.setlayoutparams(lpp);
  invalidate();
 }
}

设置不同scaletype效果,简单试几个效果:

fitxy:

Android仿京东首页画轴效果

centercrop:

Android仿京东首页画轴效果

matrix:

Android仿京东首页画轴效果

观察一下,好像那个效果都不是很好,不过matrix拉开的效果和预期需要的是一样的,不过用matrix之后,就没有办法设置其他scaletype了,没办法把图片进行缩放了,这肿么办呢,其实很简单,只需要把显示的图片提前进行一下缩放就可以了.

处理图片相关:

 /**
 * 设置paintview
 *
 * @param paintview
 */
 public void setpaintview(imageview paintview) {
 if (null == paintview) {
  log.e(tag, "设置的view为空");
  return;
 }
 // 处理图片,对图片按照屏幕宽高比进行缩放
 bitmap bp = drawabletobitamp(paintview.getdrawable());
 paintview.setimagebitmap(scalebitmal(bp));
 // 设置缩放形式
 paintview.setscaletype(imageview.scaletype.matrix);
 mpaintview = paintview;
 }
 /**
 * drawable转bitmap
 *
 * @param drawable
 * @return
 */
 private bitmap drawabletobitamp(drawable drawable) {
 if (null == drawable) {
  return null;
 }
 if (drawable instanceof bitmapdrawable) {
  bitmapdrawable bd = (bitmapdrawable) drawable;
  return bd.getbitmap();
 }
 int w = drawable.getintrinsicwidth();
 int h = drawable.getintrinsicheight();
 bitmap bitmap = bitmap.createbitmap(w, h, bitmap.config.argb_8888);
 canvas canvas = new canvas(bitmap);
 drawable.setbounds(0, 0, w, h);
 drawable.draw(canvas);
 return bitmap;
 }


 /**
 * 按照屏幕宽高缩放图片
 *
 * @param bp
 * @return
 */
 private bitmap scalebitmal(bitmap bp) {
 // 宽度比例
 float scalew = (float) screenwidth / (float) bp.getwidth();
 // 高度比例
 float scaleh = (float) screenheight / (float) bp.getheight();
 // 矩阵,用于缩放图片
 matrix matrix = new matrix();
 matrix.postscale(scalew, scaleh);
 // 缩放后的图片
 bitmap scalebp = bitmap.createbitmap(bp, 0, 0, bp.getwidth(), bp.getheight(), matrix, true);
 return scalebp;
 }

看一下效果:

Android仿京东首页画轴效果

效果还不错,接下来就是做一下细节上的处理,设置一个临界点,让画轴向上或者向下滚动,设置边界点,让画轴不越界等等.还有一般都是在scrollview中使用到这个效果,所以要去处理一下事件冲突,当然还有去重写一下onmeasure方法,不然会出现不显示的情况.(相信大家也遇到过scrollview里边嵌套listview导致listview显示不全)这里就不再详细介绍了.直接贴下代码.

三、完整代码

mainactivity:

package com.example.junweiliu.scrollpaintdemo;

import android.content.intent;
import android.os.bundle;
import android.os.handler;
import android.os.message;
import android.support.v7.app.appcompatactivity;
import android.view.view;
import android.widget.imageview;
import android.widget.textview;
import android.widget.toast;

import com.example.junweiliu.scrollpaintdemo.widget.scrollpaintview;

public class mainactivity extends appcompatactivity {
  private static final string tag = "mainactivity";
  /**
   * 需要显示的iv
   */
  private imageview mpaintiv;
  /**
   * 画轴
   */
  private scrollpaintview mscrollpaintview;

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);
    initview();

  }

  /**
   * 初始化控件
   */
  private void initview() {
    mpaintiv = (imageview) findviewbyid(r.id.iv_paint);
    mscrollpaintview = (scrollpaintview) findviewbyid(r.id.spv_paint);
    mscrollpaintview.setpaintview(mpaintiv);
    mpaintiv.setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view view) {
        toast.maketext(mainactivity.this, "功夫!", toast.length_short).show();
      }
    });
    mscrollpaintview.setscrollpaintcompletelistener(new scrollpaintview.scrollpaintcompletelistener() {
      @override
      public void onscrolltouch(textview tv) {
        mpaintiv.setvisibility(view.visible);
      }

      @override
      public void onscrolltop(textview tv) {
//        log.e(tag, "收缩了");
        tv.settext("拉我看看");
        if (view.visible == mpaintiv.getvisibility()) {
          mpaintiv.setvisibility(view.gone);
        }
      }

      @override
      public void onscrollbottom(textview tv) {
//        log.e(tag, "展开了");
        tv.settext("到底了");
        intent intent = new intent(mainactivity.this, detailactivity.class);
        startactivity(intent);
        // 延迟800毫秒重置位置
        new handler(new handler.callback() {
          @override
          public boolean handlemessage(message message) {
            mscrollpaintview.replacescroll();
            return false;
          }
        }).sendemptymessagedelayed(0, 600);
      }

      @override
      public void onscrollmove(textview tv) {
//        log.e(tag, "移动了");
        tv.settext("请上下拖动");
      }
    });
  }
}

scrollpaintview:

package com.example.junweiliu.scrollpaintdemo.widget;

import android.app.activity;
import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.matrix;
import android.graphics.rect;
import android.graphics.drawable.bitmapdrawable;
import android.graphics.drawable.drawable;
import android.util.attributeset;
import android.util.displaymetrics;
import android.util.log;
import android.util.typedvalue;
import android.view.gravity;
import android.view.motionevent;
import android.view.view;
import android.widget.imageview;
import android.widget.relativelayout;
import android.widget.scroller;
import android.widget.textview;

import com.example.junweiliu.scrollpaintdemo.r;

/**
 * created by junweiliu on 16/12/10.
 */
public class scrollpaintview extends relativelayout {
  /**
   * tag
   */
  private static final string tag = "scrollpaintview";
  /**
   * 默认滚轴高度
   */
  private final int default_paint_scroll_height = 25;
  /**
   * 默认滚动的速度
   */
  private final int default_scroll_speed = 1000;
  /**
   * 默认分割点高度
   */
  private final int default_partition_node = 150;
  /**
   * 默认画轴文字大小
   */
  private final int default_paint_scroll_txt_size = 16;
  /**
   * scroller
   */
  private scroller mscroller;
  /**
   * 滚轴iv
   */
  private imageview mpaintscrollimageview;
  /**
   * 滚轴tv
   */
  private textview mpaintscrolltextview;
  /**
   * 图画iv
   */
  private imageview mpaintview;
  /**
   * 画轴图
   */
  private bitmap mpaintscrollbp;
  /**
   * 画轴高度
   */
  private int mpaintivheight;
  /**
   * 画轴文字
   */
  private string mpaintscrolltxt;
  /**
   * 画轴文字大小
   */
  private float mpaintscrolltxtsize;
  /**
   * 画轴文字颜色
   */
  private int mpaintscrolltxtcolor;
  /**
   * 图画开始时的高度
   */
  private int mpaintstartheight;
  /**
   * 上一次获取的y
   */
  private int mlasty;
  /**
   * 滚动速度
   */
  private int mscrollspeed;
  /**
   * 分隔节点
   */
  private int partitionnode;
  /**
   * 是否是向上滚动
   */
  private boolean isscrllertop = false;
  /**
   * 是否正在点击
   */
  private boolean isclick = false;
  /**
   * 布局参数
   */
  private layoutparams lpp;
  /**
   * 屏幕高度
   */
  private int screenheight;
  /**
   * 屏幕宽度
   */
  private int screenwidth;
  /**
   * 回调监听
   */
  private scrollpaintcompletelistener listener;
  /**
   * 上一次滚动的y值
   */
  private int lastscrolly;

  /**
   * 回调接口
   */
  public interface scrollpaintcompletelistener {
    /**
     * 点击时的回调
     */
    public void onscrolltouch(textview tv);

    /**
     * 收缩时的回调
     */
    public void onscrolltop(textview tv);

    /**
     * 展开时的回调
     */
    public void onscrollbottom(textview tv);

    /**
     * 滚动中的回调
     */
    public void onscrollmove(textview tv);

  }


  public scrollpaintview(context context) {
    this(context, null);
  }

  public scrollpaintview(context context, attributeset attrs) {
    this(context, attrs, 0);
  }

  public scrollpaintview(context context, attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);
    // 获取属性
    typedarray ta = context.obtainstyledattributes(attrs, r.styleable.scrollpaintview);
    mpaintivheight = (int) ta.getdimension(r.styleable.scrollpaintview_paintscrollheight, typedvalue.applydimension(
        typedvalue.complex_unit_dip, default_paint_scroll_height, getresources().getdisplaymetrics()));
    mscrollspeed = ta.getinteger(r.styleable.scrollpaintview_scrollspeed, default_scroll_speed);
    partitionnode = ta.getinteger(r.styleable.scrollpaintview_scrollpartitionnode, default_partition_node);
    mpaintscrollbp = drawabletobitamp(ta.getdrawable(r.styleable.scrollpaintview_paintscrollsrc));
    mpaintscrolltxt = ta.getstring(r.styleable.scrollpaintview_paintscrolltxt);
    mpaintscrolltxtcolor = ta.getcolor(r.styleable.scrollpaintview_paintscrolltxtcolor, color.black);
    mpaintscrolltxtsize = px2sp(ta.getdimensionpixelsize(r.styleable.scrollpaintview_paintscrolltxtsize, default_paint_scroll_txt_size));
    ta.recycle();
    init();
    makepaintscroll();
    handleview();
  }

  /**
   * 设置paintview
   *
   * @param paintview
   */
  public void setpaintview(imageview paintview) {
    if (null == paintview) {
      log.e(tag, "设置的view为空");
      return;
    }
    // 处理图片,对图片按照屏幕宽高比进行缩放
    bitmap bp = drawabletobitamp(paintview.getdrawable());
    paintview.setimagebitmap(scalebitmal(bp));
    // 设置缩放形式
    paintview.setscaletype(imageview.scaletype.matrix);
    mpaintview = paintview;
  }

  /**
   * 设置回调
   */
  public void setscrollpaintcompletelistener(scrollpaintcompletelistener listener) {
    if (null != listener) {
      this.listener = listener;
    }
  }

  /**
   * 初始化
   */
  private void init() {
    mscroller = new scroller(getcontext());
    lpp = new layoutparams(layoutparams.match_parent, layoutparams.match_parent);
    // 获取屏幕信息
    displaymetrics displaymetrics = new displaymetrics();
    ((activity) getcontext()).getwindowmanager().getdefaultdisplay()
        .getmetrics(displaymetrics);
    // 屏幕高度
    screenheight = displaymetrics.heightpixels;
    // 屏幕宽度
    screenwidth = displaymetrics.widthpixels;
  }


  /**
   * 创建滚轴
   */
  private void makepaintscroll() {
    // 如果已经存在,则不再创建
    if (null != mpaintscrollimageview || null != mpaintscrolltextview) {
      return;
    }
    // 创建滚轴
    mpaintscrollimageview = new imageview(getcontext());
    layoutparams lp = new layoutparams(layoutparams.match_parent, layoutparams.match_parent);
    lp.height = mpaintivheight;
    mpaintscrollimageview.setlayoutparams(lp);
    mpaintscrollimageview.setscaletype(imageview.scaletype.fit_xy);
    mpaintscrollimageview.setimagebitmap(null == mpaintscrollbp ? makedefaultscroll() : mpaintscrollbp);
    addview(mpaintscrollimageview);
    // 创建文字
    mpaintscrolltextview = new textview(getcontext());
    layoutparams lpt = new layoutparams(layoutparams.match_parent, layoutparams.match_parent);
    lpt.height = mpaintivheight;
    mpaintscrolltextview.setlayoutparams(lpt);
    mpaintscrolltextview.settext(null == mpaintscrolltxt ? "" : mpaintscrolltxt);
    mpaintscrolltextview.settextsize(mpaintscrolltxtsize);
    mpaintscrolltextview.settextcolor(mpaintscrolltxtcolor);
    mpaintscrolltextview.setgravity(gravity.center);
    addview(mpaintscrolltextview);
  }


  /**
   * 测量方法
   *
   * @param widthmeasurespec
   * @param heightmeasurespec
   */
  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    super.onmeasure(widthmeasurespec, heightmeasurespec);
    if (null != mpaintview && gettop() + mpaintivheight != mpaintview.getheight()) {
      // 重新设置图画高度
      mpaintstartheight = gettop() + mpaintivheight / 2;
      lpp.height = mpaintstartheight;
      mpaintview.setlayoutparams(lpp);
    }
    // 测量状态栏高度
    rect frame = new rect();
    ((activity) getcontext()).getwindow().getdecorview().getwindowvisibledisplayframe(frame);
    int statusbarheight = frame.top;
    // 高度为屏幕高度减去状态栏高度和top的高度
    setmeasureddimension(screenwidth, screenheight - gettop() - statusbarheight);
  }

  /**
   * 处理view
   */
  private void handleview() {
    mpaintscrollimageview.setontouchlistener(new ontouchlistener() {
      @override
      public boolean ontouch(view view, motionevent event) {
        if (null == mpaintview) {
          log.e(tag, "设置的view为空");
          return true;
        }
        // 获取点击的xy坐标
        int x = (int) event.getrawx();
        int y = (int) event.getrawy();
        int action = event.getaction();
        switch (action) {
          case motionevent.action_down: {
            // 请求处理点击事件
            requestdisallowintercepttouchevent(true);
            isclick = true;
            mlasty = y;
            if (!mscroller.isfinished()) { // 如果上次的调用没有执行完就取消。
              mscroller.abortanimation();
            }
            if (null != listener) {
              listener.onscrolltouch(mpaintscrolltextview);
            }
            return true;
          }
          case motionevent.action_move: {
            // 移动的距离
            int dy = y - mlasty;
            mlasty = y;
            // 滑动
            scrollby(0, -dy);
            // 如果是向上滑动并且是在初始位置,则不去做处理
            if (getscrolly() >= 0 && dy <= 0) {
              lpp.height = mpaintstartheight;
              mpaintview.setlayoutparams(lpp);
              scrollto(0, 0);
              return true;
            }
            // 如果是向下滑动并且超过屏幕高度,则不去处理
            if (math.abs(getscrolly()) >= getheight() - mpaintivheight && dy >= 0) {
              lpp.height = mpaintstartheight + getheight() - mpaintivheight;
              mpaintview.setlayoutparams(lpp);
              scrollto(0, -(getheight() - mpaintivheight));
              return true;
            }
            // 滚动回调
            if (null != listener) {
              listener.onscrollmove(mpaintscrolltextview);
            }
            // 重新设置显示的控件高度
            if (math.abs(getscrolly()) > 0) {
              lpp.height = mpaintstartheight + math.abs(getscrolly());
              mpaintview.setlayoutparams(lpp);
            }
            return true;
          }
          case motionevent.action_up:
            // 恢复事件处理
            requestdisallowintercepttouchevent(false);
            isclick = false;
            // 没有发生移动
            if (getscrolly() >= 0) {
              if (null != listener) {
                listener.onscrolltop(mpaintscrolltextview);
              }
              return true;
            }
            if (-getscrolly() < partitionnode) {  // 如果小于临界值,则返回起始坐标
              // xy都从滑动的距离回去,最后一个参数是多少毫秒内执行完这个动作。
              isscrllertop = true;
              mscroller.startscroll(getscrollx(), getscrolly(), -getscrollx(), -getscrolly(), mscrollspeed);
            } else {  // 如果大于临界值,则展开
              isscrllertop = false;
              mscroller.startscroll(getscrollx(), getscrolly(), -getscrollx(), -(getheight() - (-getscrolly()) - mpaintivheight), mscrollspeed);
            }
            invalidate();
            return true;
        }
        return false;
      }
    });
  }


  /**
   * 滑动处理
   */
  @override
  public void computescroll() {
    if (mscroller.computescrolloffset()) { // 计算新位置,并判断上一个滚动是否完成。
      // 请求处理点击事件,防止父控件滑动
      requestdisallowintercepttouchevent(true);
      scrollto(mscroller.getcurrx(), mscroller.getcurry());
      // 重新设置显示的控件高度
      if (0 < math.abs(mscroller.getcurry())) {
        if (!isscrllertop) {
          lpp.height = mpaintstartheight + math.abs(mscroller.getcurry()) + mpaintivheight / 2;
        } else {
          lpp.height = mpaintstartheight + math.abs(mscroller.getcurry()) - mpaintivheight / 2;
        }
      } else {
        lpp.height = mpaintstartheight;
      }
      mpaintview.setlayoutparams(lpp);
      invalidate();
    } else {
      // 重新设置画图高度,防止高度异常
      if (mpaintview.getheight() > mpaintstartheight + math.abs(mscroller.getcurry()) && !isscrllertop && mscroller.getstarty() > 0) {
        lpp.height = mpaintstartheight + math.abs(mscroller.getcurry());
        mpaintview.setlayoutparams(lpp);
      }
    }
    // 防止多次调用
    if (lastscrolly != mscroller.getcurry()) {
      // 收缩完成
      if (mscroller.getcurry() >= 0 && !isclick) {
        if (null != listener) {
          listener.onscrolltop(mpaintscrolltextview);
        }
      }
      // 展开完成
      if (-mscroller.getcurry() >= getheight() - mpaintivheight && !isclick) {
        if (null != listener) {
          listener.onscrollbottom(mpaintscrolltextview);
        }
      }
      lastscrolly = mscroller.getcurry();
    }
  }

  /**
   * 重置滚动
   */
  public void replacescroll() {
    // 重置信息
    scrollto(0, 0);
    mscroller.setfinaly(0);
    lastscrolly = 0;
    lpp.height = mpaintstartheight;
    mpaintview.setlayoutparams(lpp);
    if (null != listener) {
      listener.onscrolltop(mpaintscrolltextview);
    }
  }

  /**
   * drawable转bitmap
   *
   * @param drawable
   * @return
   */
  private bitmap drawabletobitamp(drawable drawable) {
    if (null == drawable) {
      return null;
    }
    if (drawable instanceof bitmapdrawable) {
      bitmapdrawable bd = (bitmapdrawable) drawable;
      return bd.getbitmap();
    }
    int w = drawable.getintrinsicwidth();
    int h = drawable.getintrinsicheight();
    bitmap bitmap = bitmap.createbitmap(w, h, bitmap.config.argb_8888);
    canvas canvas = new canvas(bitmap);
    drawable.setbounds(0, 0, w, h);
    drawable.draw(canvas);
    return bitmap;
  }


  /**
   * 按照屏幕宽高缩放图片
   *
   * @param bp
   * @return
   */
  private bitmap scalebitmal(bitmap bp) {
    // 宽度比例
    float scalew = (float) screenwidth / (float) bp.getwidth();
    // 高度比例
    float scaleh = (float) screenheight / (float) bp.getheight();
    // 矩阵,用于缩放图片
    matrix matrix = new matrix();
    matrix.postscale(scalew, scaleh);
    // 缩放后的图片
    bitmap scalebp = bitmap.createbitmap(bp, 0, 0, bp.getwidth(), bp.getheight(), matrix, true);
    return scalebp;
  }

  /**
   * 设置默认的滚轴
   *
   * @return
   */
  private bitmap makedefaultscroll() {
    bitmap defaultbp = bitmap.createbitmap(screenwidth, mpaintivheight,
        bitmap.config.argb_8888);
    //填充颜色
    defaultbp.erasecolor(color.parsecolor("#ff0000"));
    return defaultbp;

  }


  /**
   * 将px值转换为sp值,保证文字大小不变
   */
  public int px2sp(float pxvalue) {
    final float fontscale = getcontext().getresources().getdisplaymetrics().scaleddensity;
    return (int) (pxvalue / fontscale + 0.5f);
  }

}

activity_main:

<?xml version="1.0" encoding="utf-8"?>
<relativelayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#eeeeee"
    tools:context="com.example.junweiliu.scrollpaintdemo.mainactivity">
  <scrollview
      android:layout_width="match_parent"
      android:layout_height="match_parent">
    <relativelayout android:layout_width="match_parent"
            android:layout_height="match_parent">
      <!--头部图片部分-->
      <imageview
          android:id="@+id/iv_banner"
          android:layout_width="match_parent"
          android:layout_height="200dp"
          android:scaletype="fitxy"
          android:src="@mipmap/show_banner"/>
      <!--中间内容部分-->
      <linearlayout
          android:id="@+id/ll_first"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_below="@+id/iv_banner"
          android:layout_margintop="20dp"
          android:orientation="horizontal"
          android:padding="16dp">
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_a"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="艺术片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_b"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="怀旧片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_c"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="科幻片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_d"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="动画片"
              android:textcolor="#666666"/>
        </linearlayout>
      </linearlayout>
      <linearlayout
          android:id="@+id/ll_sencond"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_below="@+id/ll_first"
          android:layout_margintop="20dp"
          android:orientation="horizontal"
          android:padding="16dp">
        <linearlayout

            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_a"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="艺术片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_b"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="怀旧片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_c"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="科幻片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_d"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="动画片"
              android:textcolor="#666666"/>
        </linearlayout>
      </linearlayout>
      <linearlayout
          android:id="@+id/ll_threeth"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_below="@+id/ll_sencond"
          android:layout_margintop="20dp"
          android:orientation="horizontal"
          android:padding="16dp">
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_a"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="艺术片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_b"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="怀旧片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_c"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="科幻片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_d"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="动画片"
              android:textcolor="#666666"/>
        </linearlayout>
      </linearlayout>
      <linearlayout
          android:id="@+id/ll_fourth"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_below="@+id/ll_threeth"
          android:layout_margintop="20dp"
          android:orientation="horizontal"
          android:padding="16dp">
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_a"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="艺术片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_b"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="怀旧片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginright="16dp"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_c"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="科幻片"
              android:textcolor="#666666"/>
        </linearlayout>
        <linearlayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal"
            android:orientation="vertical">
          <imageview
              android:layout_width="80dp"
              android:layout_height="120dp"
              android:scaletype="fitxy"
              android:src="@mipmap/movie_playbill_d"/>
          <textview
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_margintop="10dp"
              android:gravity="center"
              android:text="动画片"
              android:textcolor="#666666"/>
        </linearlayout>
      </linearlayout>

      <!--需要显示的图-->
      <imageview
          android:id="@+id/iv_paint"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:scaletype="matrix"
          android:src="@mipmap/show_img"
          android:visibility="gone"/>
      <!--画轴控件-->
      <com.example.junweiliu.scrollpaintdemo.widget.scrollpaintview
          android:id="@+id/spv_paint"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:layout_below="@+id/iv_banner"
          app:paintscrollheight="25dp"
          app:paintscrollsrc="@mipmap/paint_scroll_img"
          app:paintscrolltxt="拉我看看"
          app:paintscrolltxtcolor="#ff000000"
          app:paintscrolltxtsize="16sp"
      >
      </com.example.junweiliu.scrollpaintdemo.widget.scrollpaintview>
    </relativelayout>
  </scrollview>
</relativelayout>

attr:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <!--画轴的高度-->
  <attr name="paintscrollheight" format="dimension"/>
  <!--画轴的图片-->
  <attr name="paintscrollsrc" format="reference"/>
  <!--画轴文字-->
  <attr name="paintscrolltxt" format="string"/>
  <!--画轴文字颜色-->
  <attr name="paintscrolltxtcolor" format="color"/>
  <!--画轴文字大小-->
  <attr name="paintscrolltxtsize" format="dimension"/>
  <!--滚动速度-->
  <attr name="scrollspeed" format="integer"/>
  <!--分割节点-->
  <attr name="scrollpartitionnode" format="integer"/>
  <declare-styleable name="scrollpaintview">
    <attr name="paintscrollheight"/>
    <attr name="paintscrollsrc"/>
    <attr name="paintscrolltxt"/>
    <attr name="paintscrolltxtcolor"/>
    <attr name="paintscrolltxtsize"/>
    <attr name="scrollspeed"/>
    <attr name="scrollpartitionnode"/>
  </declare-styleable>
</resources>

四、问题

滚动的时间不宜设置太短,因为动态设置imageview高度时可能出现绘制速度赶不上滚动的速度,会出现错位,当然时间设置太短,也看不到这种滑动的效果了.暂时想到的做法就是这样,应该还会有更好的方法.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。