Android实现ViewPager剧中放大效果

news2024/12/29 8:25:30

效果图

实现方式核心思想是自定义PageTransformer继承ViewPager.PageTransformer,精确控制每一个page的动效。

PageTransformer的transformPage方法并不会区分当前的page是哪一个,所以需要我们自己去识别,我的方法是每个page添加一个text显示position,在PageTransformer中获取Text显示的内容来区分,实际使用的时候将textVew隐藏就行了

package com.example.anchorviewpagedemo;

import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.widget.ViewPager2;

/*
居中效果
 */
public class OverlayTransformerLan5 implements ViewPager.PageTransformer {
    //    public static final String TAG = OverlayTransformerLan2.class.getSimpleName();
    public static final String TAG = "YinTest_";

    public float mOffset = 40 * 2 - 20;
    public int viewPageMarginHorizontal = 30;
    public float screenWidth;
    private Context mContext;
    private float mMinScale;
    public ViewPager mViewPager;
    private int saveIndex = -1;
    private int leftMostPageIndex = -1;
    private int leftPageIndex = -1;
    private int currentPageIndex = -1;
    private int rightPageIndex = -1;
    private int rightMostPageIndex = -1;
    private int dataSize = -1;

    public OverlayTransformerLan5(float minScale) {
        mMinScale = minScale;
    }

    public OverlayTransformerLan5(Context context, ViewPager viewPager, int size, float minScale) {
        mMinScale = minScale;
        mContext = context;
        mViewPager = viewPager;
        dataSize = size;
        //适配viewPage的边距,左右各10dp
        viewPageMarginHorizontal = Utils.dp2Px(mContext, viewPageMarginHorizontal);
        screenWidth = mContext.getResources().getDisplayMetrics().widthPixels;
    }

    @Override
    public void transformPage(@NonNull View view, float position) {
//        view.setAlpha(0.5f);
        int pageWidth = view.getWidth();
        int pageHeight = view.getHeight();
        int cardViewWidth = view.findViewById(R.id.card_view).getWidth();
        final float cardMargin = (pageWidth - cardViewWidth) / 2f;
        TextView mTvPosition = view.findViewById(R.id.tv_position);

        int viewIndex = Integer.parseInt(mTvPosition.getText().toString());

        view.setPivotY(pageHeight / 2f);
        view.setPivotX(pageWidth / 2f);

//        Log.i("YinTest_", "transformPage position=" + position  + ",pageWidth = " + pageWidth  + ",viewIndex = "+viewIndex);
        if (viewIndex == leftMostPageIndex) {
            transformMostLeftPage(view, position, cardMargin, cardViewWidth, pageWidth);
        } else if (viewIndex == leftPageIndex) {
            transformLeftPage(view, position, cardMargin, cardViewWidth, pageWidth);
        } else if (viewIndex == currentPageIndex) {
            transformCenterPage(view, position, cardMargin, cardViewWidth, pageWidth);
        } else if (viewIndex == rightPageIndex) {
            transformRightPage(view, position, cardMargin, cardViewWidth, pageWidth);
        } else if (viewIndex == rightMostPageIndex) {
            transformMostRightPage(view, position, cardMargin, cardViewWidth, pageWidth);
        }
    }

    public boolean isOutLimit(float initPosition, float position) {
        if (position > initPosition + 1 || position < initPosition - 1) {
            return true;
        }
        return false;
    }

    private void transformMostLeftPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {

        if (isOutLimit(-2, position)) {
            return;
        }

        float scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale;
        //view.setScaleX(scaleFactor);
        view.setScaleY(scaleFactor);
        float anchorLeft = cardMargin + cardViewWidth;//左页左边的锚点
        float startPosition = pageWidth * 2;
        view.setTranslationZ(position);
        view.setPivotX(0);
        //初始状态position=-2.0
        if (position == -2) {
            view.setTranslationX(startPosition);
        }
        //向右滑动
        if (position > -2 && position < -1) {
            //startPosition~anchorLeft   逆滑动
            float translationX = (-position - 1) * startPosition + (position + 2) * anchorLeft;
            view.setTranslationX(translationX);
        }
        //向左滑动
        if (position < -2 && position > -3) {
            //startPosition~anchorLeft  保持其实际位置不变,不影响其他页面翻转
//            Log.i("YinTest_", " 最左页 向左滑动 position=" + position + ",translationX = " + (-position - 1));
            view.setTranslationX(startPosition + (-(position + 2)) * pageWidth);
        }


        //变为右页(相对于起始位置)
        if (position == -1) {
            view.setTranslationX(anchorLeft);
        }
        //变为左页(相对于起始位置)
        if (position == -3) {
            //向左滑动保持不变,但变为左页后跳转到正常显示位置
            view.setTranslationX(0);
        }
    }

    private void transformLeftPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {
        if (isOutLimit(-1, position)) {
            return;
        }
//        Log.i("YinTest_", " position=" + position  + ",cardMargin = " + cardMargin);
        //初始状态position=-1.0,viewIndex = 0
        float scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale;
        //view.setScaleX(scaleFactor);
        view.setScaleY(scaleFactor);
        float anchorLeft = cardMargin + cardViewWidth;//左页左边的锚点
        view.setTranslationZ(position);
        view.setPivotX(0);
//            view.setAlpha(0.5f);

        if (position == -1) {
            //初始状态 position == -1
            view.setTranslationX(anchorLeft);
        }
        if (position < -1 && position > -2) {
            //向左滑动 anchorLeft ~ pageWidth*2
            view.setTranslationX((position+2)*anchorLeft + (-2*position-2) * pageWidth);
        }
        //向右滑动
        if (position > -1 && position < 0) {
            //anchorLeft ~ 0
            view.setTranslationX((-position) * anchorLeft);
        }
        //变为左页(相对于起始位置)
        if (position == -2) {
            view.setTranslationX(pageWidth*2);
        }
        //变为右叶(相对于起始位置)
        if (position == 0) {
            //左页变为当前页 position =0.0
            view.setTranslationX(0);
        }
    }

    private void transformCenterPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {
        if (isOutLimit(0, position)) {
            return;
        }
        float anchorLeft = cardMargin + cardViewWidth;
        //初始状态 position=0.0,viewIndex = 1
        //向左滑动
        if (position > -1 && position < 0) {
            //0 ~ anchorLeft
            view.setTranslationX(-position * anchorLeft);

            float scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale;
//                view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
            view.setPivotX(0);
            view.setTranslationZ(position);
        }
        //变为左页(相对于起始位置)
        if (position == -1) {
            view.setTranslationX(anchorLeft);
        }

        float anchorRight = -(cardMargin + cardViewWidth);
        //向右滑动
        if (position < 1 && position > 0) {
            //0~anchorRight
            view.setTranslationX(position * anchorRight);

            float scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale;
//                view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);
            view.setPivotX(pageWidth);
            view.setTranslationZ(-position);
        }

        //变为右页(相对于起始位置)
        if (position == 1) {
            view.setTranslationX(anchorRight);
        }
    }

    private void transformRightPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {
        if (isOutLimit(1, position)) {
            return;
        }
//        Log.i("YinTest_", "右页 position=" + position  + ",cardMargin = " + cardMargin);
        //初始状态 position=1.0,viewIndex = 2
        float anchorRight = -(cardMargin + cardViewWidth);//右页右边的锚点
        view.setTranslationZ(-position);
        view.setPivotX(0);
        float scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale;
        //view.setScaleX(scaleFactor);
        view.setScaleY(scaleFactor);
        if (position == 1) {
            //初始状态
            view.setTranslationX(anchorRight);
        }
        //向左滑动
        if (position < 1 && position > 0) {
            //anchorRight ~ 0
            view.setTranslationX((position) * anchorRight);

        }
        //变为当左页(相对于起始位置)
        if (position == 0) {
            view.setTranslationX(0);
        }
        //向右滑动
        if (position > 1 && position < 2) {
            // anchorRight ~ -pageWidth*2
            view.setTranslationX((2-position)*anchorRight + (2*position-2) * -pageWidth);
        }
        //变为右页(相对于起始位置)
        if (position == 2) {
            view.setTranslationX(-pageWidth*2);
        }
    }

    private void transformMostRightPage(View view, float position, float cardMargin, int cardViewWidth, int pageWidth) {
        if (isOutLimit(2, position)) {
            return;
        }
        float startPosition = -pageWidth * 2;
//        Log.i("YinTest_", "最右页 position=" + position  + ",cardMargin = " + cardMargin);
        //初始状态 position=2.0
        float anchorRight = -(cardMargin + cardViewWidth);//右页右边的锚点
        view.setTranslationZ(-position);
        view.setPivotX(0);
        float scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale;
        //view.setScaleX(scaleFactor);
        view.setScaleY(scaleFactor);
        //初始状态position=-2.0
        if (position == 2) {
            view.setTranslationX(startPosition);
        }
        //向左滑动 2~1
        if (position < 2 && position > 1) {
            //逆滑动 startPosition ~ anchorRight
//            Log.i("YinTest_", " 最右页 向左滑动 position=" + position + ",translationX = " + (-position - 1));
            float translationX = (position - 1) * startPosition - (position - 2) * anchorRight;
            view.setTranslationX(translationX);
        }
        //变为左页(相对于起始位置)
        if (position == 1) {
            view.setTranslationX(anchorRight);
        }
        //向右滑动
        if (position > 2 && position < 3) {
            //startPosition~anchorLeft  保持其实际位置不变,不影响其他页面翻转
//            Log.i("YinTest_", " 最左页 向左滑动 position=" + position + ",translationX = " + (-position - 1));
            view.setTranslationX(startPosition - (position - 2) * pageWidth);
        }
        //变为右页(相对于起始位置)
        if (position == 3) {
            //向右滑动保持不变,但变为右页后跳转到正常显示位置
            view.setTranslationX(0);
        }
    }

    public void setCurrentPageIndex(int index) {
        int currentPageIndex = index % dataSize;

        this.leftMostPageIndex = checkIndex(currentPageIndex, -2);
        this.leftPageIndex = checkIndex(currentPageIndex, -1);
        this.currentPageIndex = currentPageIndex;
        this.rightPageIndex = checkIndex(currentPageIndex, 1);
        this.rightMostPageIndex = checkIndex(currentPageIndex, 2);

//        Log.i("YinTest_", "setCurrentPageIndex " + leftMostPageIndex+"," + leftPageIndex+"," + currentPageIndex+"," + rightPageIndex+"," + rightMostPageIndex);
    }

    public int checkIndex(int index, int offset) {
        if ((index + offset) < 0) {
            return dataSize + index + offset;
        } else if ((index + offset) >= dataSize) {
            return index + offset - dataSize;
        } else {
            return index + offset;
        }
    }
}

完整Demo:

https://download.csdn.net/download/y280903468/89871333

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2202604.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nuxt.js 应用中的 page:transition:finish 钩子详解

title: Nuxt.js 应用中的 page:transition:finish 钩子详解 date: 2024/10/10 updated: 2024/10/10 author: cmdragon excerpt: page:transition:finish 是 Nuxt.js 中的一个事件钩子,专门用于处理页面过渡效果结束后的逻辑。这一钩子在页面过渡的 onAfterLeave 事件之后…

qt+opengl 实现纹理贴图,平移旋转,绘制三角形,方形

1 首先qt 已经封装了opengl&#xff0c;那么我们就可以直接用了&#xff0c;这里面有三个函数需要继承 virtual void initializeGL() override; virtual void resizeGL(int w,int h) override; virtual void paintGL() override; 这三个函数是实现opengl的重要函数。 2 我们…

【NLP自然语言处理】03 - 使用Anaconda创建新的环境/pycharm切换环境

NLP基础阶段&#xff1a;创建新的虚拟环境 第一步&#xff1a;查看有多少个虚拟环境 conda env list 第二步&#xff1a;创建一个新的虚拟环境&#xff0c;起个名字&#xff1a;nlpbase 打开anconda prompt终端&#xff0c;输入命令: conda create -n nlpbase python3.10 第三步…

基于xml配置文件的Spring事务

在项目中对事务属性通常传播属性&#xff0c;回滚属性&#xff0c;隔离级别&#xff0c;超时属性都取默认值&#xff0c;只有只读属性会如下的配置&#xff1a; 什么意思&#xff1a;Service层你的类里的方法&#xff0c;以get&#xff0c;find&#xff0c;select等开头的方法是…

如何进行数据中心负载测试的自动化?

数据中心负载测试的自动化是一种通过使用软件工具和脚本来模拟大量用户访问数据中心的过程&#xff0c;以评估其性能、稳定性和可扩展性的方法。以下是进行数据中心负载测试自动化的一些建议&#xff1a; 市场上有许多负载测试工具可供选择&#xff0c;如LoadRunner、JMeter、…

【图论】(二)图论基础与路径问题

图论基础与路径问题 图的构造邻接矩阵邻接表 所有可达路径邻接矩阵存储邻接表存储 字符串接龙有向图的完全可达性 图的构造 这里仅对图论路径问题中图的构造做整理总结归纳&#xff0c;具体详细相关概念请参考代码随想录上的整理总结&#xff1a; 图论理论基础深度优先搜索理…

C语言函数栈帧的创建与销毁(32)

文章目录 前言一、什么是函数栈帧&#xff1f;二、理解函数栈帧能解决什么问题&#xff1f;三、函数栈帧的创建和销毁解析什么是栈&#xff1f;认识相关寄存器和汇编指令 四、解析函数栈帧的创建和销毁预备知识函数的调用堆栈准备环境转到反汇编函数栈帧的创建函数栈帧的销毁 五…

采用反相正基准电压电路的反相运算放大器

1 简介 本设计使用采用反相正基准电压的反相放大器将 –5V 至 –1V 的输入信号转换为 3.3V 至 0.05V 的输出电压。该电路可用于将传感器负输出电压转换为可用的 ADC 输入电压范围。 2 设计目标 2.1 输入 2.2 输出 2.3 电源 3 电路设计 根据设计目标&#xff0c;最终设计的电…

2.1类和对象(上)

本篇博客来梳理类和对象的基础知识 一、类的定义 1&#xff0e;类定义格式 &#xff08;1&#xff09;关键字&#xff1a;class。类中的变量称为类的属性/成员变量&#xff0c;类中的函数称为类的方法/成员函数 &#xff08;2&#xff09;为区分成员变量&#xff0c;一般会加…

MES管理系统对中小企业有哪些帮助

MES管理系统解决方案对中小企业具有显著的帮助&#xff0c;主要体现在以下几个方面&#xff1a; 一、提升生产效率 MES管理系统能够实时监控生产过程&#xff0c;提供准确的生产数据和及时的反馈。这种实时监控与数据分析能力&#xff0c;使中小企业能够精准把握生产脉搏&…

如何应对动态图片大小变化?Python解决网页图片截图难题

背景介绍 随着互联网的发展&#xff0c;许多网站&#xff0c;尤其是电商平台&#xff0c;如京东&#xff08;JD.com&#xff09;&#xff0c;为了提升用户体验&#xff0c;采用了许多动态内容加载技术。当我们使用爬虫获取商品图片时&#xff0c;往往会遇到一些棘手问题&#…

中科星图GVE(案例)——AI提取指定采样区域的建筑物范围

目录 简介 函数 gve.Image.fromGeometry(geometry,source,options) gve.Services.AI.buildingExtraction(fromGridRes) 代码 结果 ​编辑 知识星球 机器学习 简介 要提取指定采样区域的建筑物范围&#xff0c;可以使用遥感图像处理和计算机视觉技术。以下是一种可能的…

软考攻略/超详细/系统集成项目管理工程师/基础知识分享14

5.4 软件实现 5.4.1 软件配置管理&#xff08;掌握&#xff09; 软件配置管理&#xff08;SCM&#xff09;是一种标识、组织和控制修改的技术。软件配置管理应用于整个软件工程过程。 SCM活动的目标就是标识变更、控制变更、确保变更正确 SCM的目的是使错误降为最小&#xff0…

申报审批|基于springBoot的入校申报审批系统设计与实现(附项目源码+论文+数据库)

私信或留言即免费送开题报告和任务书&#xff08;可指定任意题目&#xff09; 目录 一、摘要 二、相关技术 三、系统设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取 一、摘要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出…

数据库中间件 -- MyCat

1、什么是数据库中间件 数据库中间件(Database Middleware)是一种位于应用程序与数据库管理系统(DBMS)之间的软件层。它的主要目的是为应用程序提供更加高效、可靠和透明的数据库访问,同时解决多种数据库管理问题。 The domain name Mycat.io is for sale 1.1、常见的数…

新质生产力在制造业中的“新”主要体现在哪

新质生产力&#xff0c;以其独特的技术创新、模式变革和思维升级&#xff0c;正逐步重塑制造业的面貌&#xff0c;引领其走向更加智能化、绿色化和高效化的未来。 一、技术创新&#xff1a;驱动产业升级的核心引擎 新质生产力在制造业中的首要“新”&#xff0c;体现在技术创新…

Chromium 书签加载过程分析c++

一、书签存储路径: %localappdata%\Chromium\User Data\Default\Bookmarks %localappdata%\Chromium\User Data\Default\Bookmarks.bak 【备份文件】 本机测试存储的Bookmarks文件如下&#xff08;未加密的可以直接打开&#xff09;&#xff1a; {"checksum": &q…

Allegro平台正式进军匈牙利市场,Allegro怎么快速上架产品?

近日&#xff0c;波兰电商平台Allegro正式宣布进军匈牙利市场&#xff0c;此举标志着Allegro在中东欧地区的扩张步伐再次加速。作为一家在波兰本土享有盛誉的电商平台&#xff0c;Allegro此举无疑为匈牙利乃至整个中欧地区的电商市场注入了新的活力。 Allegro此次进军匈牙利市…

比较三组迭代次数的变化

(A,B)---6*30*2---(0,1)(1,0) 让A是结构5&#xff0c;让B全是0。收敛误差为7e-4&#xff0c;收敛199次取迭代次数平均值&#xff0c;得到迭代次数为129535.3 (A,B)---6*30*2&#xff08;5&#xff09;---(0,1)(1,0) 然后让A分别是0&#xff0c;1&#xff0c;2&#xff0c;3&a…

服装生产管理:SpringBoot技术实现

1 绪论 1.1 研究背景 当今时代是飞速发展的信息时代。在各行各业中离不开信息处理&#xff0c;这正是计算机被广泛应用于信息管理系统的环境。计算机的最大好处在于利用它能够进行信息管理。使用计算机进行信息控制&#xff0c;不仅提高了工作效率&#xff0c;而且大大的提高…