uniapp适配android、ios的引导页、首页布局

1,558 阅读6分钟

uniapp适配Android、Ios的引导页和首页布局

真是很久没来掘金写文章了,最近一直在学习Nest和Next这些后端知识,忙只是一方面,更多的还是懒吧。其实今年来北京工作之后,完全独立挑大梁来写app收获还是蛮多的,但是我一般忙完就完事,着急学习自己的东西去,没有把工作中遇到的一些问题及时总结。这点感觉很不好,以后尽量把工作中遇到的有价值的问题总结下来,也算是给自己这段时间工作的复习,也能锻炼自己的表达能力。

引导页

原型图和需求

微信截图_20240722143529.png

需求大致是这样:一共有三页,每页有2-3组图片,产品想要炫酷的视觉效果

我接收到需求后,首先想的是gif图,于是让UI帮我做了一张12帧的gif,大家来感受一下效果

01.gif

不知道大家感受怎么样,放到手机来模拟的时候有些模糊、有些卡顿,且占用空间很大,一张12帧的图片已经20M+, 整个应用不过才30M的情况下,绝对接受不了这种情况,于是我就放弃的gif,想要用代码来实现。

思路

留给我的开发时间并不多,只有半天,自己本身css能力一般,按照gif这样估计最多做出来一页,所以我和产品决定阉割掉一部分动效,做三页。

  • UI负责把每条图片列表切图给我
  • 引导页用swiper实现,这样页面切换动画可以省时间
  • 第一页水平做动画两两一组,交替实现动画
  • 第二页垂直做动画,交替实现
  • 第三页原图和AI图在一个父盒子下,原图动态改变宽度来实现交替播放
  • 每页文字和按钮通过position:fixed置底
  • 最后一页手动加上滑动事件,可以不点击按钮进入首页

代码实现

  • template布局
<view class="swiperLayout">
    <swiper
        :current="current"
	class="swiper"
	duration="350"
	@change="change"
        :indicator-active-color=" '#FFF272' "
        :indicator-color="'#ccc'"
        indicator-dots="true"
    >
        <swiper-item class="swiperItem">
            <view class="itemLayout">
                <image
                        class="img an1"
                        src="@/static/guide/guide1_1.png"
                        mode="scaleToFill"
                />
                <image
                        class="img an2"
                        src="@/static/guide/guide1_2.png"
                        mode="scaleToFill"
                />
                <image
                        class="img an1"
                        src="@/static/guide/guide1_3.png"
                        mode="scaleToFill"
                />
                <image
                        class="img an2"
                        src="@/static/guide/guide1_4.png"
                        mode="scaleToFill"
                />
                <view class="buttonBox">
                    <view class="title">海量模板</view>
                    <view class="button" @click="next(1)">下一步</view>
                </view>
            </view>
        </swiper-item>
        <swiper-item class="swiperItem">
                <view class="itemLayout">
                        <view class="guide2Box">
                            <image
                                class="img2 an3"
                                src="@/static/guide/guide2_1.png"
                                mode="scaleToFill"
                            />
                            <image
                                class="img2 an4"
                                src="@/static/guide/guide2_2.png"
                                mode="scaleToFill"
                            />
                            <image
                                class="img2 an3"
                                src="@/static/guide/guide2_3.png"
                                mode="scaleToFill"
                            />
                        </view>
                        <view class="buttonBox">
                            <view class="title">5000+云端照片存储</view>
                            <view class="button" @click="next(2)">下一步</view>
                        </view>
                </view>
        </swiper-item>
        <swiper-item
                class="swiperItem"
                @touchstart="handlerStart($event)"
                @touchmove="handerMove($event)"
        >
            <view class="itemLayout">
                <view class="guide3">
                <-- img3动态改变自己的宽度,来实现动画效果 -->
                    <image
                        class="img3 an5 z"
                        src="@/static/guide/guide3_1.png"
                        mode="aspectFill"
                    />
                    <image
                        class="img4 "
                        src="@/static/guide/guide3_2.png"
                        mode="heightFix"
                    />
                </view>
                <view class="buttonBox">
                            <view class="title">高清照片,无水印无广告</view>
                            <view class="button" @click="toIndex">继续</view>
                        </view>
                    </view>
            </swiper-item>
    </swiper>
</view>
  • css部分
.swiper {
	width: 100vw;
	height: 100vh;
    background: #000;
	.swiperItem {
		.itemLayout {
			display: flex;
			flex-direction: column;
			align-items: center;
            padding-top: 60rpx;
			.img {
				width: 220vw;
                height: 35vw;
                margin: 20rpx 0 0rpx 0;
			}
            .img2 {
				width: 30vw;
                height:  256vw;
			}
			.title {
                color: $themeColor;
				margin-top: 40rpx;
				text-align: center;
				font-size: 36rpx;
				font-weight: 600;
				margin-bottom: 40rpx;
			}
			.button {
				background: $themeColor;
				color: #000;
				height: 88rpx;
				line-height: 88rpx;
				width: 88%;
				text-align: center;
				border-radius: 48rpx;
				font-size: 32rpx;
				font-weight: 600;
			}
		}
        .guide2Box{
            display: flex;
            justify-content: space-evenly;
            width: 100%;
            overflow: hidden;
            height: 70vh;
        }
	}
}

// 动画1  执行三秒 匀速 无限次 镜像执行
.an1 {
    animation: guide1 3s linear infinite  alternate-reverse ; 
}

// 水平X轴正向
@keyframes guide1 {
    from {
        transform: translateX(0);
    }
    50% {
        transform: translateX(200rpx);
    }
    to {
        transform: translateX(400rpx);
    }
}

.an2 {
    animation: guide2  3s linear  infinite  alternate-reverse   ;
}
// 水平X轴负向
@keyframes guide2 {
    from {
        transform: translateX(0);
    }
    50% {
        transform: translateX(-200rpx);
    }
    to {
        transform: translateX(-400rpx);
    }
}

.an3 {
    animation: guide3  3s linear infinite  alternate-reverse ;
}
// 水平正向 但是起始点要给负数 不然会有空缺的部分
@keyframes guide3 {
    from {
        transform: translateY(-500rpx);
    }
    50% {
        transform: translateY(-250rpx);
    }
    to {
        transform: translateY(0rpx);
    }
}

.an4 {
    animation: guide4  3s linear infinite alternate-reverse  ;
}
// 水平负向
@keyframes guide4 {
    from {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-250rpx);
    }
    to {
        transform: translateY(-500rpx);
    }
}
.buttonBox{
    position: fixed;
    bottom: 120rpx;
    width: 80vw;
    display: flex;
    flex-direction: column;
    align-items: center;
    z-index: 999;
}
// 最后一页动画 父盒子开启相对定位
.guide3{
    position: relative;
    width: 100%;
    height: 100%;
    // 两张图片都开始绝对定位  一左一右分布
    .img3{
        position: absolute;
        top: 0;
        left: 0;
        height: 147vw;
        border-right: 12rpx solid #fff;
    }
    .img4{
        position: absolute;
        top: 0;
        right: 0;
        height: 147vw;
    }
}
// img3 缩小自己的宽度来实现动画
.an5 {
    animation: changeImg 2s linear infinite  alternate-reverse;
}
@keyframes changeImg {
    from {
        width: 0%;
    }
    to {
        width: 100%;
    }
}

.z{
    z-index: 99;
}
  • js部分
data() {
		return {
			current: 0,
			// 触摸事件用到的数据
			touchInfo: {
				touchX: "",
				touchY: "",
			},
		};
	},
	methods: {
		next(num) {
			this.current = num;
		},
		change(e) {
			this.current = e.detail.current;
		},
		toIndex() {
			uni.switchTab({ url: "/pages/index/index" });
		},
		handlerStart(e) {
			let { clientX, clientY } = e.changedTouches[0];
			this.touchInfo.touchX = clientX;
			this.touchInfo.touchY = clientY;
		},
		handerMove(e) {
			let { clientX, clientY } = e.changedTouches[0];
			let diffX = clientX - this.touchInfo.touchX,
				diffY = clientY - this.touchInfo.touchY,
				absDiffX = Math.abs(diffX),
				absDiffY = Math.abs(diffY),
				type = "";
            if (absDiffX > 50 && absDiffX > absDiffY) {
                type = diffX >= 0 ? "right" : "left";
            }
			if (absDiffY > 50 && absDiffX < absDiffY) {
				type = diffY < 0 ? "up" : "down";
			}
			if(type === 'left'){
                this.toIndex()
            }
		},
	},

最终效果

动画2.gif

首页布局

原型图和需求

  • 画风

微信截图_20240722144340.png

  • 贴纸

微信截图_20240722143558.png

  • 换脸

微信截图_20240722144351.png

上面三图均为UI设计。首页的模板接口截止到目前(7.22)一共三种类型:styler(画风)、sticker(贴纸)、face_swap(换脸),本来按照UI的设计来看,每个分类的样式应该是固定写死的,我只需要v-for去不同的组件就可以,正当我写了一半时,很快老板的需求又下来:每个分类可能会杂糅在一起。说白了就是某个分类里可能既有画风、又有换脸、又有贴纸

思路

  • 分析需求

在一个父组件中渲染所有的数据,根据不同的type 进入不同的子组件,三个子组件分别对应画风、贴纸、换脸,其中贴纸数据中有一个mode字段,根据mode展示轮播、九宫格、一大八小的布局,这其中一大八小最不好实现。

一大八小的布局
  • 将数据中的九张模板图片进行分组(剔除第一张,因为第一张要做“一大”),分为两组布局是上下分布(display:flex)实现,同时将第一张和分组的view盒子的父元素也要开启display:flex

  • 编译到chrome调试 看html结构

Snipaste_2024-07-22_15-25-39.png

  • 代码
 <scroll-view class="scroll_view" scroll-x="true">
    <image
        class="img"
        :src="sceneItem.json_content.cover_image_list[0].path"
        mode="scaleToFill"
    />
    <view>
        <view
            class="Item_2"
            v-for="(Item, index) in columnData"
            :key="index"
        >
            <view v-for="item in Item" :key="item.id">
                <image
                    class="ss"
                    :src="item.path"
                    mode="scaleToFill"
                />
            </view>
        </view>
    </view>
</scroll-view>
...
computed:{
    columnData() {
        if (this.sceneItem.json_content.display_mode === "2") {
            const setData = this.sceneItem.json_content.cover_image_list.filter(
                (item, index) => index > 0
            );
            const resultArray = setData.reduce(
                (acc, cur, index) => {
                    const targetIndex = index % 2;
                    acc[targetIndex].push(cur);
                    return acc;
                },
                Array.from(Array(2), () => [])
            );
            return resultArray;
        }
    },
}
...
::v-deep .uni-scroll-view-content {
    display: flex;
}
 .scroll_view {
        white-space: nowrap;
        .img {
            min-width: 324rpx;
            height: 324rpx;
            border-radius: 24rpx;
            margin-right: 24rpx;
        }
        .Item {
            display: inline-block;
            .img {
                width: 324rpx;
                height: 324rpx;
                border-radius: 24rpx;
                margin-right: 24rpx;
            }
        }
        .Item_2 {
            display: flex;
            .ss {
                width: 158rpx;
                height: 158rpx;
                margin-right: 12rpx;
                border-radius: 16rpx;
            }
        }
    }

实现效果

动画3.gif