文档章节

ViewPager背景实现Parallax(平差化)效果

军歌
 军歌
发布于 2014/10/14 14:51
字数 848
阅读 953
收藏 0
点赞 0
评论 0
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;

@SuppressLint("NewApi")
public class ParallaxViewPager extends ViewPager {

    public static final int FIT_WIDTH = 0;
    public static final int FIT_HEIGHT = 1;
    public static final float OVERLAP_FULL = 1f;
    public static final float OVERLAP_HALF = 0.5f;
    public static final float OVERLAP_QUARTER = 0.25f;
    private static final float CORRECTION_PERCENTAGE = 0.01f;
    public Bitmap bitmap;
    private Rect source, destination;
    private int scaleType;
    private int chunkWidth;
    private int projectedWidth;
    private float overlap;
    private OnPageChangeListener secondOnPageChangeListener;

    public ParallaxViewPager(Context context) {
        super(context);
        init();
    }

    public ParallaxViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        source = new Rect();
        destination = new Rect();
        scaleType = FIT_HEIGHT;
        overlap = OVERLAP_HALF;

        setOnPageChangeListener(new OnPageChangeListener() {
            @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                if (bitmap != null) {
                    source.left = (int) Math.floor((position + positionOffset - CORRECTION_PERCENTAGE) * chunkWidth);
                    source.right = (int) Math.ceil((position + positionOffset + CORRECTION_PERCENTAGE) * chunkWidth + projectedWidth);
                    destination.left = (int) Math.floor((position + positionOffset - CORRECTION_PERCENTAGE) * getWidth());
                    destination.right = (int) Math.ceil((position + positionOffset + 1 + CORRECTION_PERCENTAGE) * getWidth());
                    invalidate();
                }

                if (secondOnPageChangeListener != null) {
                    secondOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
                }
            }

            @Override public void onPageSelected(int position) {
                if (secondOnPageChangeListener != null) {
                    secondOnPageChangeListener.onPageSelected(position);
                }
            }

            @Override public void onPageScrollStateChanged(int state) {
                if (secondOnPageChangeListener != null) {
                    secondOnPageChangeListener.onPageScrollStateChanged(state);
                }
            }
        });
    }

    @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        destination.top = 0;
        destination.bottom = h;
        if (getAdapter() != null && bitmap != null)
            calculateParallaxParameters();
    }

    private void calculateParallaxParameters() {
        if (bitmap.getWidth() < getWidth() && bitmap.getWidth() < bitmap.getHeight() && scaleType == FIT_HEIGHT) {
            Log.w(ParallaxViewPager.class.getName(), "Invalid bitmap bounds for the current device, parallax effect will not work.");
        }

        final float ratio = (float) getHeight() / bitmap.getHeight();
        if (ratio != 1) {
            switch (scaleType) {
                case FIT_WIDTH:
                    source.top = (int) ((bitmap.getHeight() - bitmap.getHeight() / ratio) / 2);
                    source.bottom = bitmap.getHeight() - source.top;
                    chunkWidth = (int) Math.ceil((float) bitmap.getWidth() / (float) getAdapter().getCount());
                    projectedWidth = chunkWidth;
                    break;
                case FIT_HEIGHT:
                default:
                    source.top = 0;
                    source.bottom = bitmap.getHeight();
                    projectedWidth = (int) Math.ceil(getWidth() / ratio);
                    chunkWidth = (int) Math.ceil((bitmap.getWidth() - projectedWidth) / (float) getAdapter().getCount() * overlap);
                    break;
            }
        }
    }

    /**
     * Sets the background from a resource file.
     *
     * @param resid
     */
    @Override public void setBackgroundResource(int resid) {
        bitmap = BitmapFactory.decodeResource(getResources(), resid);
    }

    /**
     * Sets the background from a Drawable.
     *
     * @param background
     */
    @Override public void setBackground(Drawable background) {
        bitmap = ((BitmapDrawable) background).getBitmap();
    }

    /**
     * Deprecated.
     * Sets the background from a Drawable.
     *
     * @param background
     */
    @Override public void setBackgroundDrawable(Drawable background) {
        bitmap = ((BitmapDrawable) background).getBitmap();
    }

    /**
     * Sets the background from a bitmap.
     *
     * @param bitmap
     * @return The ParallaxViewPager object itself.
     */
    public ParallaxViewPager setBackground(Bitmap bitmap) {
        this.bitmap = bitmap;
        return this;
    }

    /**
     * Sets how the view should scale the background. The available choices are:
     * <ul>
     * <li>FIT_HEIGHT - the height of the image is resized to matched the height of the View, also stretching the width to keep the aspect ratio. The non-visible part of the bitmap is divided into equal parts, each of them sliding in at the proper position.</li>
     * <li>FIT_WIDTH - the width of the background image is divided into equal chunks, each taking up the whole width of the screen.</li>
     * </ul>
     *
     * @param scaleType
     * @return
     */
    public ParallaxViewPager setScaleType(final int scaleType) {
        if (scaleType != FIT_WIDTH && scaleType != FIT_HEIGHT)
            throw new IllegalArgumentException("Illegal argument: scaleType must be FIT_WIDTH or FIT_HEIGHT");
        this.scaleType = scaleType;
        return this;
    }

    /**
     * Sets the amount of overlapping with the setOverlapPercentage(final float percentage) method. This is a number between 0 and 1, the smaller it is, the slower is the background scrolling.
     *
     * @param percentage
     * @return The ParallaxViewPager object itself.
     */
    public ParallaxViewPager setOverlapPercentage(final float percentage) {
        if (percentage <= 0 || percentage >= 1)
            throw new IllegalArgumentException("Illegal argument: percentage must be between 0 and 1");
        overlap = percentage;
        return this;
    }

    /**
     * Recalculates the parameters of the parallax effect, useful after changes in runtime.
     *
     * @return The ParallaxViewPager object itself.
     */
    public ParallaxViewPager invalidateParallaxParameters() {
        calculateParallaxParameters();
        return this;
    }

    @Override protected void onDraw(Canvas canvas) {
        if (bitmap != null)
            canvas.drawBitmap(bitmap, source, destination, null);
    }

    public void addOnPageChangeListener(OnPageChangeListener listener) {
        secondOnPageChangeListener = listener;
    }
}

1、创建布局XML parallaxviewpager。

        通过XML或下列方法设置背景:

               

  • setBackgroundResource(int resid)

  • setBackground(Drawable background) or setBackgroundDrawable(Drawable background)

  • setBackground(Bitmap bitmap)


    指定视图的规模应该与setscaletype背景(scaletype)方法。

选择下列参数:

fit_height    意味着图像的高度调整到相匹配的观点的高度,同时拉伸宽度保持纵横比。 

                  位图的不可见的部分分成相等的部分,他们每个人都在适当的位置的滑动。这是默认值。

fit_width     背景图像的宽度被分成相等的块,每个占据整个屏幕宽度。

                   这种模式是不寻常的视差效应,为背景的滚动速度等于视图的速度。

设定的setoverlappercentage重叠(最后的浮动比例)的方法。这是一个0和1之间的数字,小,速度慢的背景滚动。默认值是百分之50。这只适用于fit_height。


    final ParallaxViewPager parallaxViewPager = new ParallaxViewPager(this);
    parallaxViewPager.setAdapter(new MyPagerAdapter());
    parallaxViewPager.setBackgroundResource(R.drawable.nagy);
    setContentView(parallaxViewPager);


© 著作权归作者所有

共有 人打赏支持
军歌
粉丝 9
博文 86
码字总数 43501
作品 0
深圳
程序员
Android NestedScrollView/ScrollView包裹ViewPager自适应高度

Android NestedScrollView/ScrollView包裹ViewPager自适应高度 当Android的NestedScrollView/ScrollView这类滚动View包裹ViewPager时候,ViewPager中的Fragment包含的又是一系列高度值不固定...

zhangphil ⋅ 05/12 ⋅ 0

打造万能的BannerView(ViewPager)无限轮播图

为什么写这篇文章,因为在网上看到的绝大多数BannerView实现了右无限轮播图,甚至没有实现无限轮播图,说成是无限轮播图,实现了左右无限轮播图的,并没有做性能上的优化。 先看张效果图 工程...

Steven_520 ⋅ 05/11 ⋅ 0

你真的会用Fragment吗?Fragment复用的那些事儿

作者: @怪盗kidou 如需转载不得删除本文中的任何内容(含本段) 如果博客中有不恰当之处欢迎在原文中留言交流 https://www.jianshu.com/p/31f013df7580 大家好,好像距离上次发布博客好像又...

怪盗kidou ⋅ 05/24 ⋅ 0

Android Fragment 监听hide和show

setUserVisibleHint方法耳熟能详,可是仅仅适用于ViewPager,他是ViewPager中手动调用的,但是正常情况下我们该怎么监听呢? 我们也手动调用不就好了 上addFragment代码 private Fragment m...

qq_36523667 ⋅ 05/10 ⋅ 0

从零开发Android视频点播APP

第1章 课程介绍,技术选型 本章将向大家介绍本课程你们学到什么,项目功能模块有哪些,并对技术进行分解,方便大家有针对性的准备和学习,同时会将项目结构设计好,为后面项目的开发做好基础准...

13269051240 ⋅ 05/21 ⋅ 0

从零开发Android视频点播APP视频课程 点播APP实战教程

第1章 课程介绍,技术选型 本章将向大家介绍本课程你们学到什么,项目功能模块有哪些,并对技术进行分解,方便大家有针对性的准备和学习,同时会将项目结构设计好,为后面项目的开发做好基础准...

17087075817 ⋅ 05/14 ⋅ 0

图片预览组件PhotoView

图片预览组件PhotoView PhotoView是一款图片预览组件,广泛应用于大图的查看。该组件支持图片手势缩放、旋转等功能。它可以很好的和ViewPager、Picasso等组件结合,实现各种复杂的功能。...

大学霸 ⋅ 05/29 ⋅ 0

想把GridView添加到ViewPager里面。报空指针异常

用TabLayout和ViewPager关联后,想把GridView添加到ViewPager里面。报空指针异常。不知道哪里写错了 04-12 08:39:37.363 25278-25278/? E/AndroidRuntime: FATAL EXCEPTION: main Process: ...

csl232 ⋅ 04/13 ⋅ 0

ScrollView 嵌套 ViewPager,ViewPager内容不显示问题

解决办法: 1.简单点的就是重写ViewPager //自定义ScrollView嵌套的ViewPager可显示public class ViewPagerForScrollView extends ViewPager { } 但是有个缺点是有时候几个Fragment高度一样了...

王先森oO ⋅ 05/24 ⋅ 0

轻轻松松实现RecyclerView对齐效果

在开发过程中,对齐效果是一个很常见的功能:比如我们使用ViewPager,或者是使用画廊效果的FancyCoverFlow,都无一例外的要求某一个Item居中对齐。比如看看Google Play,它实现了滑动停止后I...

r17171709 ⋅ 05/22 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

如何使用serverchan微信推送告警

之前实现推送告警信息到微信的方法有如下几种: 1、通过企业公众号实现----收费: 2、通过QQ邮箱,在微信平台上开启收到邮件进行提醒; 3、第三方告警平台API,一般也是收费的; 不过最近看文...

问题终结者 ⋅ 31分钟前 ⋅ 0

TCP的RPC

RPC就是远程方法调用(Remote Process Call ),包含了客户端和服务端,涉及了对象的序列化传输。 1.服务端启动,注册远程调用的类2.客户端发送请求信息包含类、方法、参数的一些信息、序列化传...

Cobbage ⋅ 52分钟前 ⋅ 0

IOS-UI UI初步代码布局添加事件

ISO开发界面,UI是必须学习的一部分,其实很早之前想学来了,一直没有沉下心来学习。看到IOS的代码风格和布局就别扭的不行,跟java代码和android布局比较显得不是那么方便,所以一直到现在。...

京一 ⋅ 今天 ⋅ 0

浅谈OpenDaylight的二次开发

OpenDaylight作为一款开源SDN网络控制器,依托于强大的社区支持以及功能特性,成为了目前主流的SDN网络控制器开发平台。在比较稳定的OpenDaylight Helium版本中,已经为开发者提供了大量的网...

wangxuwei ⋅ 今天 ⋅ 0

API 开发中可选择传递 token 接口遇到的一个坑

在做 API 开发时,不可避免会涉及到登录验证,我使用的是jwt-auth 在登录中会经常遇到一个token过期的问题,在config/jwt.php默认设置中,这个过期时间是一个小时,不过为了安全也可以设置更...

等月人 ⋅ 今天 ⋅ 0

Java NIO之文件处理

程序要操作本地操作系统的一个文件,可以分为以下三个部分: 对文件位置的操作 对文件的操作 对文件内容的操作 其中,对文件内容的操作在 Java NIO之Channel 中已经有了介绍,通过FileChann...

士别三日 ⋅ 今天 ⋅ 0

Maven的pom.xml配置文件详解

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.......

小海bug ⋅ 今天 ⋅ 0

解决httpclient超时设置不生效的问题

最近公司有项目需要通过http调用第三方服务,且第三方服务偶有超时,故需要设置一定的超时时间防止不响应的情况出现。 初始设置如下: [java] view plain copy //超时设置 RequestConfig re...

Mr_Tea伯奕 ⋅ 今天 ⋅ 0

过滤器Filter和拦截器HandlerInterceptor

过滤器 依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要...

hutaishi ⋅ 今天 ⋅ 0

Redis入门详解(转)

Redis入门详解 Redis简介 Redis安装 Redis配置 Redis数据类型 Redis功能 持久化 主从复制 事务支持 发布订阅 管道 虚拟内存 Redis性能 Redis部署 Redis应用场景 Redis总结 Redis简介: Redi...

xiaoyaoyoufang ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部