Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >关于安卓下拉刷新时的悬浮菜单栏

关于安卓下拉刷新时的悬浮菜单栏

作者头像
用户4458175
发布于 2020-02-12 08:39:23
发布于 2020-02-12 08:39:23
1.5K00
代码可运行
举报
文章被收录于专栏:andy的小窝andy的小窝
运行总次数:0
代码可运行

最近在github上遇到一个下拉刷新上拉加载的项目--BGARefreshLayout。地址。使用里面的BGARefreshLayout嵌套一个

BGAStickyNavLayout 能很好解决上面banner,中间TabLayout(下拉时悬浮),下面一个ViewPaper或RecycleView。

BGAStickyNavLayout 里面只能是包含三个子控件且第三个子控件为ViewPager时,其adapter必须是FragmentPagerAdapter或者          FragmentStatePagerAdapter。

ps:百度了一下也发现一个类似的不过不知道可不可以多个控件。地址。下面是BGAStickyNavLayout 的源码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Copyright 2015 bingoogolapple
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.bingoogolapple.refreshlayout;

import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.webkit.WebView;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import android.widget.OverScroller;
import android.widget.ScrollView;

import cn.bingoogolapple.refreshlayout.util.BGARefreshScrollingUtil;

/**
 * 作者:王浩 邮件:bingoogolapple@gmail.com
 * 创建时间:15/10/28 上午2:32
 * 描述:
 */
public class BGAStickyNavLayout extends LinearLayout {
    private View mHeaderView;
    private View mNavView;
    private View mContentView;

    private View mDirectNormalView;
    private RecyclerView mDirectRecyclerView;
    private AbsListView mDirectAbsListView;
    private ScrollView mDirectScrollView;
    private WebView mDirectWebView;
    private ViewPager mDirectViewPager;

    private View mNestedContentView;
    private View mNestedNormalView;
    private RecyclerView mNestedRecyclerView;
    private AbsListView mNestedAbsListView;
    private ScrollView mNestedScrollView;
    private WebView mNestedWebView;

    private OverScroller mOverScroller;
    private VelocityTracker mVelocityTracker;
    private int mTouchSlop;
    private int mMaximumVelocity;
    private int mMinimumVelocity;

    private boolean mIsInControl = true;

    private float mLastDispatchY;
    private float mLastTouchY;

    public BGARefreshLayout mRefreshLayout;

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

    private void init(Context context) {
        setOrientation(VERTICAL);

        mOverScroller = new OverScroller(context);
        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = configuration.getScaledTouchSlop();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
    }

    @Override
    public void setOrientation(int orientation) {
        if (VERTICAL == orientation) {
            super.setOrientation(VERTICAL);
        }
    }

    @Override
    public void onFinishInflate() {
        super.onFinishInflate();

        if (getChildCount() != 3) {
            throw new IllegalStateException(BGAStickyNavLayout.class.getSimpleName() + "必须有且只有三个子控件");
        }

        mHeaderView = getChildAt(0);
        mNavView = getChildAt(1);
        mContentView = getChildAt(2);

        if (mContentView instanceof AbsListView) {
            mDirectAbsListView = (AbsListView) mContentView;
            mDirectAbsListView.setOnScrollListener(mLvOnScrollListener);
        } else if (mContentView instanceof RecyclerView) {
            mDirectRecyclerView = (RecyclerView) mContentView;
            mDirectRecyclerView.addOnScrollListener(mRvOnScrollListener);
        } else if (mContentView instanceof ScrollView) {
            mDirectScrollView = (ScrollView) mContentView;
        } else if (mContentView instanceof WebView) {
            mDirectWebView = (WebView) mContentView;
        } else if (mContentView instanceof ViewPager) {
            mDirectViewPager = (ViewPager) mContentView;
            mDirectViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    regetNestedContentView();
                }
            });
        } else {
            mDirectNormalView = mContentView;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        measureChild(mContentView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec) - getNavViewHeight(), MeasureSpec.EXACTLY));
    }

    @Override
    public void computeScroll() {
        if (mOverScroller.computeScrollOffset()) {
            scrollTo(0, mOverScroller.getCurrY());
            invalidate();
        }
    }

    public void fling(int velocityY) {
        mOverScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, getHeaderViewHeight());
        invalidate();
    }

    @Override
    public void scrollTo(int x, int y) {
        if (y < 0) {
            y = 0;
        }

        int headerViewHeight = getHeaderViewHeight();
        if (y > headerViewHeight) {
            y = headerViewHeight;
        }

        if (y != getScrollY()) {
            super.scrollTo(x, y);
        }
    }

    /**
     * 获取头部视图高度,包括topMargin和bottomMargin
     *
     * @return
     */
    private int getHeaderViewHeight() {
        MarginLayoutParams layoutParams = (MarginLayoutParams) mHeaderView.getLayoutParams();
        return mHeaderView.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
    }

    /**
     * 获取导航视图的高度,包括topMargin和bottomMargin
     *
     * @return
     */
    private int getNavViewHeight() {
        MarginLayoutParams layoutParams = (MarginLayoutParams) mNavView.getLayoutParams();
        return mNavView.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
    }

    /**
     * 头部视图是否已经完全隐藏
     *
     * @return
     */
    private boolean isHeaderViewCompleteInvisible() {
        // 0表示x,1表示y
        int[] location = new int[2];
        getLocationOnScreen(location);
        int contentOnScreenTopY = location[1] + getPaddingTop();

        mNavView.getLocationOnScreen(location);
        MarginLayoutParams params = (MarginLayoutParams) mNavView.getLayoutParams();
        int navViewTopOnScreenY = location[1] - params.topMargin;

        if (navViewTopOnScreenY == contentOnScreenTopY) {
            return true;
        } else {
            return false;
        }
    }

    private void initVelocityTrackerIfNotExists() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
    }

    private void recycleVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        float currentTouchY = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastDispatchY = currentTouchY;
                break;
            case MotionEvent.ACTION_MOVE:
                float differentY = currentTouchY - mLastDispatchY;
                mLastDispatchY = currentTouchY;
                if (isContentViewToTop() && isHeaderViewCompleteInvisible()) {
                    if (differentY >= 0 && !mIsInControl) {
                        mIsInControl = true;

                        return resetDispatchTouchEvent(ev);
                    }

                    if (differentY <= 0 && mIsInControl) {
                        mIsInControl = false;

                        return resetDispatchTouchEvent(ev);
                    }
                }
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    private boolean resetDispatchTouchEvent(MotionEvent ev) {
        MotionEvent newEvent = MotionEvent.obtain(ev);

        ev.setAction(MotionEvent.ACTION_CANCEL);
        dispatchTouchEvent(ev);

        newEvent.setAction(MotionEvent.ACTION_DOWN);
        return dispatchTouchEvent(newEvent);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        float currentTouchY = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastTouchY = currentTouchY;
                break;
            case MotionEvent.ACTION_MOVE:
                float differentY = currentTouchY - mLastTouchY;
                if (Math.abs(differentY) > mTouchSlop) {
                    if (!isHeaderViewCompleteInvisible() || (isContentViewToTop() && isHeaderViewCompleteInvisible() && mIsInControl)) {
                        mLastTouchY = currentTouchY;
                        return true;
                    }
                }
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        initVelocityTrackerIfNotExists();
        mVelocityTracker.addMovement(event);

        float currentTouchY = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (!mOverScroller.isFinished()) {
                    mOverScroller.abortAnimation();
                }

                mLastTouchY = currentTouchY;
                break;
            case MotionEvent.ACTION_MOVE:
                float differentY = currentTouchY - mLastTouchY;
                mLastTouchY = currentTouchY;
                if (Math.abs(differentY) > 0) {
                    scrollBy(0, (int) -differentY);
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                recycleVelocityTracker();
                if (!mOverScroller.isFinished()) {
                    mOverScroller.abortAnimation();
                }
                break;
            case MotionEvent.ACTION_UP:
                mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                int initialVelocity = (int) mVelocityTracker.getYVelocity();
                if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                    fling(-initialVelocity);
                }
                recycleVelocityTracker();
                break;
        }
        return true;
    }

    public boolean isContentViewToTop() {
        if (mDirectNormalView != null) {
            return true;
        }

        if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mDirectWebView)) {
            return true;
        }

        if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mDirectScrollView)) {
            return true;
        }

        if (BGARefreshScrollingUtil.isAbsListViewToTop(mDirectAbsListView)) {
            return true;
        }

        if (BGARefreshScrollingUtil.isRecyclerViewToTop(mDirectRecyclerView)) {
            return true;
        }

        if (mDirectViewPager != null) {
            return isViewPagerContentViewToTop();
        }

        return false;
    }

    private boolean isViewPagerContentViewToTop() {
        if (mNestedContentView == null) {
            regetNestedContentView();
        }

        if (mDirectNormalView != null) {
            return true;
        }

        if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mNestedWebView)) {
            return true;
        }

        if (BGARefreshScrollingUtil.isScrollViewOrWebViewToTop(mNestedScrollView)) {
            return true;
        }

        if (BGARefreshScrollingUtil.isAbsListViewToTop(mNestedAbsListView)) {
            return true;
        }

        if (BGARefreshScrollingUtil.isRecyclerViewToTop(mNestedRecyclerView)) {
            return true;
        }

        return false;
    }

    /**
     * 重新获取嵌套的内容视图
     */
    private void regetNestedContentView() {
        int currentItem = mDirectViewPager.getCurrentItem();
        PagerAdapter adapter = mDirectViewPager.getAdapter();
        if (adapter instanceof FragmentPagerAdapter || adapter instanceof FragmentStatePagerAdapter) {
            Fragment item = (Fragment) adapter.instantiateItem(mDirectViewPager, currentItem);
            mNestedContentView = item.getView();

            // 清空之前的
            mNestedNormalView = null;
            mNestedAbsListView = null;
            mNestedRecyclerView = null;
            mNestedScrollView = null;
            mNestedWebView = null;

            if (mNestedContentView instanceof AbsListView) {
                mNestedAbsListView = (AbsListView) mNestedContentView;
                mNestedAbsListView.setOnScrollListener(mLvOnScrollListener);

                if (!isHeaderViewCompleteInvisible()) {
                    mNestedAbsListView.setSelection(0);
                }
            } else if (mNestedContentView instanceof RecyclerView) {
                mNestedRecyclerView = (RecyclerView) mNestedContentView;
                mNestedRecyclerView.removeOnScrollListener(mRvOnScrollListener);
                mNestedRecyclerView.addOnScrollListener(mRvOnScrollListener);

                if (!isHeaderViewCompleteInvisible()) {
                    mNestedRecyclerView.scrollToPosition(0);
                }
            } else if (mNestedContentView instanceof ScrollView) {
                mNestedScrollView = (ScrollView) mNestedContentView;

                if (!isHeaderViewCompleteInvisible()) {
                    mNestedScrollView.scrollTo(mNestedScrollView.getScrollX(), 0);
                }
            } else if (mNestedContentView instanceof WebView) {
                mNestedWebView = (WebView) mNestedContentView;

                if (!isHeaderViewCompleteInvisible()) {
                    mNestedWebView.scrollTo(mNestedWebView.getScrollX(), 0);
                }
            } else {
                mNestedNormalView = mNestedContentView;
            }
        } else {
            throw new IllegalStateException(BGAStickyNavLayout.class.getSimpleName() + "的第三个子控件为ViewPager时,其adapter必须是FragmentPagerAdapter或者FragmentStatePagerAdapter");
        }
    }

    public void setRefreshLayout(BGARefreshLayout refreshLayout) {
        mRefreshLayout = refreshLayout;
    }

    private RecyclerView.OnScrollListener mRvOnScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            if ((newState == RecyclerView.SCROLL_STATE_IDLE || newState == RecyclerView.SCROLL_STATE_SETTLING) && mRefreshLayout != null && mRefreshLayout.shouldHandleRecyclerViewLoadingMore(recyclerView)) {
                mRefreshLayout.beginLoadingMore();
            }
        }
    };

    private AbsListView.OnScrollListener mLvOnScrollListener = new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView absListView, int scrollState) {
            if ((scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) && mRefreshLayout != null && mRefreshLayout.shouldHandleAbsListViewLoadingMore(absListView)) {
                mRefreshLayout.beginLoadingMore();
            }
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        }
    };

    public boolean shouldHandleLoadingMore() {
        if (mRefreshLayout == null) {
            return false;
        }

        if (mDirectNormalView != null) {
            return true;
        }

        if (BGARefreshScrollingUtil.isWebViewToBottom(mDirectWebView)) {
            return true;
        }

        if (BGARefreshScrollingUtil.isScrollViewToBottom(mDirectScrollView)) {
            return true;
        }

        if (mDirectAbsListView != null) {
            return mRefreshLayout.shouldHandleAbsListViewLoadingMore(mDirectAbsListView);
        }

        if (mDirectRecyclerView != null) {
            return mRefreshLayout.shouldHandleRecyclerViewLoadingMore(mDirectRecyclerView);
        }

        if (mDirectViewPager != null) {
            if (mNestedContentView == null) {
                regetNestedContentView();
            }

            if (mNestedNormalView != null) {
                return true;
            }

            if (BGARefreshScrollingUtil.isWebViewToBottom(mNestedWebView)) {
                return true;
            }

            if (BGARefreshScrollingUtil.isScrollViewToBottom(mNestedScrollView)) {
                return true;
            }

            if (mNestedAbsListView != null) {
                return mRefreshLayout.shouldHandleAbsListViewLoadingMore(mNestedAbsListView);
            }

            if (mNestedRecyclerView != null) {
                return mRefreshLayout.shouldHandleRecyclerViewLoadingMore(mNestedRecyclerView);
            }
        }

        return false;
    }

    public void scrollToBottom() {
        BGARefreshScrollingUtil.scrollToBottom(mDirectScrollView);
        BGARefreshScrollingUtil.scrollToBottom(mDirectRecyclerView);
        BGARefreshScrollingUtil.scrollToBottom(mDirectAbsListView);

        if (mDirectViewPager != null) {
            if (mNestedContentView == null) {
                regetNestedContentView();
            }
            BGARefreshScrollingUtil.scrollToBottom(mNestedScrollView);
            BGARefreshScrollingUtil.scrollToBottom(mNestedRecyclerView);
            BGARefreshScrollingUtil.scrollToBottom(mNestedAbsListView);
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
来来来,手把手教你做大白!
这个东西也是经常被拿来玩的一个小东西,就是通过border-radius 去自己切一个图形。
疯狂的技术宅
2019/03/28
4360
CSS3实现冰墩墩自由
CSS3代码: body { background: rgba(72, 167, 255, 0.733); overflow: hidden; width: 100%; height: 100%; } .main { width: 100px; margin: 10% auto; perspective: 300px; position: absolute; top: 20%; left: 50%; transfor
用户5997198
2022/03/28
4110
CSS3实现冰墩墩自由
冰墩墩太火了,一墩难求?Bloger用css方式呈现一人一墩
近日来,围绕冬奥的热点层出不穷。观众们眼前不断闪过一个接一个既陌生又新鲜好玩的项目,话题更迭的速度比钢架雪车还快。自然也会衍生出诸多分歧:围绕谷爱凌的国籍、苏翊鸣的分数、短道速滑赛场上几乎每一次的摔倒和判罚……这是每一届体育大赛中,都少不了的争论甚至争吵,只有冰墩墩成为了例外。
李洋博客
2022/02/18
4470
冰墩墩太火了,一墩难求?Bloger用css方式呈现一人一墩
CSS+HTML绘制2022年北京冬奥会吉祥物冰墩墩
既然买不到冰墩墩,就自己做个专属冰墩墩吧!以上代码都是本人原创,转载的话请注明出处
用户9999906
2022/09/26
3220
【Html.js——CSS布局】618 活动(蓝桥杯真题-2325)【合集】
Rossy Yan
2025/02/02
810
【Html.js——CSS布局】618 活动(蓝桥杯真题-2325)【合集】
【Html.js——页面布局】个人博客(蓝桥杯真题-1766)【合集】
通过以上步骤,HTML 和 CSS 代码协同工作,实现了一个具有导航栏、首页 banner、文章列表和右侧栏的个人博客页面布局。
Rossy Yan
2025/01/24
1470
【Html.js——页面布局】个人博客(蓝桥杯真题-1766)【合集】
【Html.js——Bug修复】找回连接的奇幻之旅(蓝桥杯真题-18555)【合集】
请在 js/index.js 文件中补充 resetableOnce 函数,实现在接收相同的函数时只执行一次。
Rossy Yan
2025/02/26
1090
【Html.js——Bug修复】找回连接的奇幻之旅(蓝桥杯真题-18555)【合集】
【Html.js——页面布局】水果摆盘(蓝桥杯真题-1767)【合集】
在需要修改部分的代码有相关提示,请仔细阅读之后,使用 flex 布局中的 align-self 和 order 完善 index.css 中的代码, 把对应的水果放在对应的盘子里面,最终效果如下:
Rossy Yan
2025/01/24
2450
【Html.js——页面布局】水果摆盘(蓝桥杯真题-1767)【合集】
HTML+CSS+JS 实现登录注册界面[通俗易懂]
鉴于小伙伴们没有csdn积分,我把代码压缩成了一个压缩包,放在了gitee上面,需要的请点击下载 点击下载
全栈程序员站长
2022/09/13
26.3K0
HTML+CSS+JS 实现登录注册界面[通俗易懂]
CSS3 Loading加载效果合集
效果1 CSS <style> .loading { width: 300px; height: 300px; position: relative; border: 1px solid gray; } .loading .line { width: 200px; height: 8px; /* margin: 50% 20px; */ position:
无道
2019/11/13
1.3K0
CSS3 Loading加载效果合集
CSS3实现雪容融自由
前几天写了一篇CSS3实现冰墩墩自由的技术文章,很多人问有没有雪容融的,今天就来啦!
用户5997198
2022/03/28
2690
CSS3实现雪容融自由
【Html.js——功能实现】布局切换(蓝桥杯真题-18556)【合集】
Rossy Yan
2025/02/21
2660
【Html.js——功能实现】布局切换(蓝桥杯真题-18556)【合集】
【CSS——功能实现】用户名片(蓝桥杯真题-2321)【合集】
选中 index.html 右键启动 Web Server 服务(Open with Live Server),让项目运行起来。
Rossy Yan
2025/02/02
1590
【CSS——功能实现】用户名片(蓝桥杯真题-2321)【合集】
700行无用 纯 CSS 祝考生 金榜高粽《1_bit 的无用 CSS 代码 》
今天才想起来这回事,没办法就急急忙忙的赶工一下,接下来我就画一下这个海报试试手了:
1_bit
2022/06/06
6440
700行无用 纯 CSS 祝考生 金榜高粽《1_bit 的无用 CSS 代码 》
【Html.js——标签导航栏】卡片化标签页(蓝桥杯真题-1765)【合集】
选中 index.html 右键启动 Web Server 服务(Open with Live Server),让项目运行起来。接着,打开环境右侧的【Web 服务】,就可以在浏览器中看到如下效果,当前显示仅有静态布局,并未实现选项卡切换功能。
Rossy Yan
2025/01/24
3210
【Html.js——标签导航栏】卡片化标签页(蓝桥杯真题-1765)【合集】
【Html.js——功能实现】蓝桥校园一卡通(蓝桥杯真题-2421)【合集】
HTML 部分主要负责构建页面的结构,创建了一个校园一卡通制卡的表单界面,包含了卡片展示区域和用户输入信息的表单区域。
Rossy Yan
2025/02/10
1930
【Html.js——功能实现】蓝桥校园一卡通(蓝桥杯真题-2421)【合集】
【CSS3——页面布局】画一只考拉(蓝桥杯真题-2341)【合集】
这段 HTML 代码构建了页面的基本结构,为绘制考拉提供了元素容器。主要通过嵌套的 <div> 元素来划分不同的部分,每个部分都有对应的类名,方便在 CSS 中进行样式设置。
Rossy Yan
2025/02/06
1850
【CSS3——页面布局】画一只考拉(蓝桥杯真题-2341)【合集】
归档 | 原生JS实现会动代码之哆啦A梦
TL;DR 项目官网:https://doraemon.jirengu.maylove.pub 源码地址:https://github.com/zkeq/Doraemon 实现原理 textDom.innerHTML = cssString.substring(0, textStartIndex); styleDom.innerHTML = cssString.substring(0, textStartIndex); 没啥好说的 完整 js 放一下 const cssString
Zkeq
2022/09/07
6680
HTML简单音乐播放器「建议收藏」
通过JS部分的代码,动态给歌曲信息模块(id为player-content1)的DOM元素添加/移除active类名。 设置CSS3动画过渡属性: transition:top 0.3s ease;来生成过渡时间0.3s,速度逐渐变慢的: 上移动画效果:top:0px; ——>top:-85px; 下移动画效果: top:-85px; ——>top:0px;
全栈程序员站长
2022/09/07
4.6K0
乐高个性化小人生成器(源代码一键复制即可运行 )
大家好,今天我要给大家介绍一个超级有趣的网页项目——乐高个性化小人生成器!这个项目可以让你随心所欲地定制属于自己的乐高小人,让它们拥有独一无二的表情和配色。
前端达人
2024/11/25
1260
乐高个性化小人生成器(源代码一键复制即可运行 )
推荐阅读
相关推荐
来来来,手把手教你做大白!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验