HarmonyOS 基础之PageSlider和PageFlipper 原创 精华

中软HOS小鸿
发布于 2021-9-24 17:56
浏览
7收藏

作者:盛禹

前言

众所周知,PageSlider是用于页面之间切换的组件,它通过响应滑动事件完成页面间的切换,而PageFlipper可能知道的人就比较少了,其实PageFlipper和PageSlider类似,都是视图切换组件,它们都继承自StackLayout,因此可以将多个component层叠在一起,每次只显示一个组件,当视图从一个component切换到另一个component时,PageFlipper支持指定动画效果。

区别:PageFlipper通过addComponent()添加component,可使用动画控制多个component之间的切换效果,是个轻量级的组件,适合展示少量静态数据;而PageSlide是由provider来提供component的,更适用复杂的视图切换,实现数据的动态加载。

下面是一个PageSlider和PageFlipper结合起来的使用效果,页面中间的卡片使用的是PageSlider,背景图片和底部的数字指示器用的是PageFlipper,通过回调将三个组件联动起来就实现了这样的效果:

HarmonyOS 基础之PageSlider和PageFlipper-鸿蒙开发者社区

正文

1.pageSlider

PageSlider可以说是鸿蒙中最常用的视图切换组件了,使用方法不用多做介绍,官方文档有详细的说明,这里主要说一下一个特殊的效果;

一屏多页效果

其实鸿蒙本身有提供一个setClipEnabled()的方法,作用是设置是否允许在组件超出其父布局时自动裁剪组件,理论上通过给pageSlider父布局设置setClipEnabled(false),加上给子组件设置合适的宽度可以实现一屏多页效果,但是经过测试并没达到效果,
这个方法我也单独拿出来在其他场景验证过确实无效,下面是验证的效果。

HarmonyOS 基础之PageSlider和PageFlipper-鸿蒙开发者社区

但是鸿蒙却提供了另外一个方法setPageMargin(),它的作用是设置PageSlider中子组件边距的,当传入一个合适的负数时(必须是负数),就能实现一屏同时显示多个子组件的效果:

HarmonyOS 基础之PageSlider和PageFlipper-鸿蒙开发者社区

动态设置缩放透明度变化

设置透明度和缩放比例就不细说了,主要就是在PageSlider子组件加载完成后和页面切换中的回调方法中改变alpha值和scale值,直接上代码:

public final class AlphaScalePageTransformer {
    /**
     * 缩放
     */
    public static final float INACTIVE_SCALE = 0.8f;
    /**
     * 透明度
     */
    public static final float INACTIVE_ALPHA = 0.5f;

    /**
     * 设置初始状态的缩放和透明度
     *
     * @param child
     * @param position
     * @param current
     */
    public static void defaultPage(ListContainer child, int position, float current) {
        if (position != current) {
            child.setAlpha(INACTIVE_ALPHA);
            child.setScaleX(INACTIVE_SCALE);
            child.setScaleY(INACTIVE_SCALE);
        }
    }

    /**
     * 设置滑动中的缩放和透明度
     *
     * @param childList
     * @param position
     * @param offset
     * @param direction
     */
    public static void transformPage(List<ListContainer> childList, int position, float offset, float direction) {
        Component child = childList.get(position);
        float scale = INACTIVE_SCALE + (1 - INACTIVE_SCALE) * (1 - Math.abs(offset));
        float alpha = INACTIVE_ALPHA + (1 - INACTIVE_ALPHA) * (1 - Math.abs(offset));
        child.setScaleX(scale);
        child.setScaleY(scale);
        child.setAlpha(alpha);
        if (direction > 0) {
            if (position < childList.size() - 1) {
                child = childList.get(position + 1);
            }
        } else {
            if (position >= 1) {
                child = childList.get(position - 1);
            }
        }
        scale = INACTIVE_SCALE + (1 - INACTIVE_SCALE) * Math.abs(offset);
        alpha = INACTIVE_ALPHA + (1 - INACTIVE_ALPHA) * Math.abs(offset);
        child.setScaleX(scale);
        child.setScaleY(scale);
        child.setAlpha(alpha);
    }
}

设置两边的component透明度和缩放效果

//设置初始状态缩放和透明度
AlphaScalePageTransformer.defaultPage(image, i, pageSlider.getCurrentPage());

//设置页面切换中缩放和透明度
pageSlider.addPageChangedListener(new PageChangedListener() {
            @Override
            public void onPageSliding(int position, float positionOffset, int positionOffsetPixels) {
                AlphaScalePageTransformer.transformPage(listContainers, position, 
                positionOffset, positionOffsetPixels);
            }
        });

2.PageFlipper(翻页器)

PageFlipper是一个翻页器,当它有两个或多个子组件时,切换过程中可以轻松设置入场动画和出场动画,以达到意想不到的效果。虽然PageFlipper的使用率远不及PageSlider,但这并不意味着PageFlipper就不强大,他能通过简单的代码实现许多动画效果,比如淘宝头条的效果,日历翻页效果,背景图淡入淡出效果等等;

常用方法

getCurrentComponent()//获取当前组件

showNext():显示下一个组件(如果当前子组件是最后一个,则显示第一个子组件)

showPrevious():显示上一个组件(如果当前子组件是第一个,则显示最后一个子组件)

getFlipInterval() :获取自动翻转时间

setFlipPeriod(int period) :设置翻转周期

startFlipping() :开启自动翻转

stopFlipping() :停止自动翻转

addComponent() :添加组件

setIncomingAnimationA() :设置转入动画

setOutgoingAnimation() :设置转出动画


下面通过设置文字翻页效果来了解下它的使用方法:

HarmonyOS 基础之PageSlider和PageFlipper-鸿蒙开发者社区

public class IndicatorComponent extends DirectionalLayout {
    /**
     * 文字大小
     */
    private static final int TEXT_SIZE = 130;
    /**
     * 动画时长
     */
    private static final int DURATION = 600;
    private PageFlipper textSwitcher;
    private Text textcomponent;

    /**
     * ItemsCountcomponent
     *
     * @param context
     * @param attrSet
     */
    public IndicatorComponent(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context);
    }

    private void init(Context context) {
        setOrientation(ComponentContainer.HORIZONTAL);
        textSwitcher = new PageFlipper(context);
        //理论上PageFlipper只需要添加两个子component就能实现动画效果,但是实际测试发现如果切换速度太快就导致子组件衔接不上出现组件消失的额情况,
        //因此这里通过实践多添加了几个子component,防止滑动过快出现bug
        textSwitcher.addComponent(createcomponentForTextSwitcher(context));
        textSwitcher.addComponent(createcomponentForTextSwitcher(context));
        textSwitcher.addComponent(createcomponentForTextSwitcher(context));
        textSwitcher.addComponent(createcomponentForTextSwitcher(context));
        addComponent(textSwitcher, new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                ComponentContainer.LayoutConfig.MATCH_CONTENT));
        textcomponent = new Text(context);
        textcomponent.setTextSize(TEXT_SIZE);
        textcomponent.setFont(Font.DEFAULT_BOLD);
        textcomponent.setTextColor(new Color(Color.getIntColor("#8cffffff")));
        addComponent(textcomponent, new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                ComponentContainer.LayoutConfig.MATCH_CONTENT));
    }

    /**
     * 创建组件
     *
     * @param context 上下文
     * @return text
     */
    private Text createcomponentForTextSwitcher(Context context) {
        Text text = new Text(context);
        text.setTextSize(TEXT_SIZE);
        text.setFont(Font.DEFAULT_BOLD);
        text.setTextColor(Color.WHITE);
        text.setLayoutConfig(new PageFlipper.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                PageFlipper.LayoutConfig.MATCH_CONTENT));
        return text;
    }

    /**
     * update
     *
     * @param newPosition   新位置
     * @param oldPosition   旧位置
     * @param totalElements 总数
     */
    public void update(int newPosition, int oldPosition, int totalElements) {
        textcomponent.setText(" / " + totalElements);
        int offset = textSwitcher.getHeight();
        if (newPosition > oldPosition) {
            //设置组件进入和退出的动画
            textSwitcher.setIncomingAnimation(createPositionAnimation(-offset, 0, 0f, 1f, DURATION));
            textSwitcher.setOutgoingAnimation(createPositionAnimation(0, offset, 1f, 0f, DURATION));
        } else if (oldPosition > newPosition) {
            textSwitcher.setIncomingAnimation(createPositionAnimation(offset, 0, 0f, 1f, DURATION));
            textSwitcher.setOutgoingAnimation(createPositionAnimation(0, -offset, 1f, 0f, DURATION));
        }
        //显示下一个组件并执行动画
        textSwitcher.showNext();
        Text text = (Text) textSwitcher.getCurrentComponent();
        text.setText(String.valueOf(newPosition + 1));
    }

    /**
     * 创建属性动画
     *
     * @param fromY
     * @param toY
     * @param fromAlpha
     * @param toAlpha
     * @param duration
     * @return
     */
    private AnimatorProperty createPositionAnimation(int fromY, int toY, float fromAlpha, float toAlpha, int duration) {
        AnimatorProperty animatorProperty = new AnimatorProperty();
        animatorProperty.setCurveType(Animator.CurveType.DECELERATE);
        animatorProperty.alphaFrom(fromAlpha);
        animatorProperty.alpha(toAlpha);
        animatorProperty.moveFromY(fromY);
        animatorProperty.moveToY(toY);
        animatorProperty.setDuration(duration);
        return animatorProperty;
    }
}

结束

以上主要介绍了PageSlider和PageFlipper的一些简单使用,最后补充一个小功能,设置渐变效果,这个简单的效果可能很多人还不知道如何设置:

首先生成一个foreground_gradient.xml

<shape
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:shape="rectangle">

    //设置填充的颜色,可以根据实际需要设置多个
    <solid
        ohos:colors="#000000,#00ffffff,#d8000000"/>
    //设置渐变方向,有三个值可供选择:linear_gradient,radial_gradient,sweep_gradient
    <gradient
        ohos:shader_type="linear_gradient"
        />
</shape>

然后给目标组件设置前景色即

ohos:foreground_element="$graphic:foreground_gradient"

更多原创内容请关注:开鸿 HarmonyOS 学院

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-9-24 17:56:21修改
14
收藏 7
回复
举报
2条回复
按时间正序
/
按时间倒序
mb609898e2cfb86
mb609898e2cfb86

文章不错,图也挺有意思的。

回复
2021-9-26 10:10:42
深开鸿
深开鸿

很实用的

回复
2021-9-27 14:05:21
回复
    相关推荐