Android开发之卡片叠层实现原理解析

Android 实现卡片堆叠,卡片管理效果(带动画) Android 实现卡片管理效果,会员卡管理效果,卡片堆叠效果 阅读详情
AI摘要

本文解析了几种不同的卡片视图组件实现方式,包括InfiniteCycleViewPager、CardSlidePanel和CardSwipeLayout等开源库。详细介绍了这些组件的工作原理、关键技术和应用场景。

转载请标明出处:
https://blog.youkuaiyun.com/AnalyzeSystem/article/details/80078954
本文出自AnalyzeSystem的博客

本篇博客只为卡片叠层相关开源库系列学习理解分析,为可能存在的类似需求定制自定义控件做一个技术累计分享。


InfiniteCycleViewPager

系统自带了横向Viewpager,没有纵向所以自定义了VerticalViewPager,然后扩展横向纵向的ViewPager:HorizontalInfiniteCycleViewPager、VerticalInfiniteCycleViewPager,自定义的InfiniteCycleManager 主要负责自定义属性的解析以及相关属性的代码设置,内部持有自定义InfiniteCycleScroller,InfiniteCycleScroller主要是修改startScroll的duration参数,VerticalInfiniteCycleViewPager构造参数传入默认1000

两个扩展ViewPager主要是一些自定义属性、listener、adapter相关的代理,都实现了ViewPageable,相关函数默认值set get都在InfiniteCycleManager,这里就不细说了,本篇核心卡片效果

InfiniteCycleManager

扩展的ViewPager会初始化InfiniteCycleManager构造函数把自定义的scroller通过反射设置给viewpager,接着通过processAttributeSet函数解析自定义属性

public InfiniteCycleManager(final Context context,final ViewPageable viewPageable,final AttributeSet attributeSet) {
        mContext = context;
        mIsVertical = viewPageable instanceof VerticalViewPager;

        mViewPageable = viewPageable;
        mCastViewPageable = (View) viewPageable;

        // Set default InfiniteViewPager
        mViewPageable.setPageTransformer(false, getInfinityCyclePageTransformer());
        mViewPageable.addOnPageChangeListener(mInfinityCyclePageChangeListener);
        mViewPageable.setClipChildren(DEFAULT_DISABLE_FLAG);
        mViewPageable.setDrawingCacheEnabled(DEFAULT_DISABLE_FLAG);
        mViewPageable.setWillNotCacheDrawing(DEFAULT_ENABLE_FLAG);
        mViewPageable.setPageMargin(DEFAULT_PAGE_MARGIN);
        mViewPageable.setOffscreenPageLimit(DEFAULT_OFFSCREEN_PAGE_LIMIT);
        mViewPageable.setOverScrollMode(OVER_SCROLL_NEVER);

        // Reset scroller and process attribute set
        resetScroller();
        processAttributeSet(attributeSet);
    }

viewPager的滑动触摸事件拦截分发也通过代理由InfiniteCycleManager来处理

 @Override
    public boolean onTouchEvent(final MotionEvent ev) {
        try {
            return mInfiniteCycleManager == null ? super.onTouchEvent(ev) :
                    mInfiniteCycleManager.onTouchEvent(ev) && super.onTouchEvent(ev);
        } catch (IllegalArgumentException e) {
            return true;
        }
    }

    @Override
    public boolean onInterceptTouchEvent(final MotionEvent ev) {
        try {
            return mInfiniteCycleManager == null ? super.onInterceptTouchEvent(ev) :
                    mInfiniteCycleManager.onInterceptTouchEvent(ev) && super.onInterceptTouchEvent(ev);
        } catch (IllegalArgumentException e) {
            return true;
        }
    }

Touch函数有个知识点:检查触摸位置是否超出界限

private void checkHitRect(final MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mHitRect.set(
                    mCastViewPageable.getLeft(), mCastViewPageable.getTop(),
                    mCastViewPageable.getRight(), mCastViewPageable.getBottom()
            );
        } else if (event.getAction() == MotionEvent.ACTION_MOVE && !mHitRect.contains(
                mCastViewPageable.getLeft() + (int) event.getX(),
                mCastViewPageable.getTop() + (int) event.getY()
        )) event.setAction(MotionEvent.ACTION_UP);
    }

以上内容并不是核心点,viewPager的滑动偏移量变化关联Item动画效果,如果你认真看了上面的代码块应该能记得这两句代码

  mViewPageable.setPageTransformer(false, getInfinityCyclePageTransformer());
  mViewPageable.addOnPageChangeListener(mInfinityCyclePageChangeListener);

该库的庐山真面目出来了:PageTransformer + OnPageChangeListener,这里补充一个知识点:

作者库里用的ViewPager.SimpleOnPageChangeListener抽象类,SimpleOnPageChangeListener抽象类实现OnPageChangeListener,重写了每个函数,我们OnPageChangeListener = new SimpleOnPageChangeListener好处可以不用重载每个函数

PageTransformer
/** 
 * Apply a property transformation to the given page.
 * 
 * @param page Apply the transformation to this page
 * @param position Position of page relative to the current front-and-center 
 *                 position of the pager. 0 is front and center. 1 is one full 
 *                 page position to the right, and -1 is one page position to the left. 
*/
public void transformPage(View view, float position)

transformPage()方法的关键在于position的理解,从doc注释来看,当前选中的item的position永远是0(这与ViewPager的OnPageChangeListener回调方法中的position不同),被选中item的前一个为-1,被选中item的后一个为1。* 其实这里文档的描述并不是完全正确的,前后item position为-1和1的前提是你没有给ViewPager设置pageMargin(通过调用viewPager.setPageMargin(int)方法设置)*。如果你设置了pageMargin,前后item的position需要分别加上(或减去,前减后加)一个偏移量(偏移量的计算方式为pageMargin / pageWidth)。
在用户滑动界面的时候,position是动态变化的,下面以左滑为例:

选中item position:0->-1 - offset (pageMargin / pageWidth)
前一个item position:-1 - offset (pageMargin / pageWidth) -> -2 - offset (pageMargin / pageWidth),再往前就以此类推
后一个item position:1 + offset (pageMargin / pageWidth) -> 0,再往后就以此类推
因此我们可以将position的值应用于setAlpha(), setTranslationX(), 或者 setScaleY()等等方法,从而实现自定义的动画效果。


transformPage函数还有个view.bringToFront()方法的调用,该方法理解可参考下面链接

https://www.cnblogs.com/zhainanJohnny/articles/3292563.html

InfiniteCycleManager 构造函数初始化时为ViewPager还设置了下面两个属性

mViewPageable.setClipChildren(DEFAULT_DISABLE_FLAG);
mViewPageable.setOffscreenPageLimit(DEFAULT_OFFSCREEN_PAGE_LIMIT);

这样ViewPager就可以同时显示多个Item,配合PageTransformer动态计算左右偏移量执行平移缩放动画

ViewPager的无限循环原理通过修改adapter实现,如果有需求如下:

触摸-1 或者1 position位置需要把滑动事件交给 0 position处理

如果有这个问题可以尝试把ViewPager的parent touch事件交给ViewPager

以前群里有人问app 土巴兔的选择装修风格的效果,实现原理也是如此,InfiniteCycleViewPager的学习分析比较粗,凑合着看吧


CardSlidePanel

该库的实现核心知识点在于ViewDragHelper和自定义ViewGroup,关于ViewDragHelper博主以前也撸过一篇博客,有兴趣可以看看

https://blog.youkuaiyun.com/AnalyzeSystem/article/details/50537927

首先来重新认识几个类:

  • OnGestureListener这个是常用的接口,作用手势识别的回调

  • OnDoubleTapListener双击监听接口

  • SimpleOnGestureListener 以实现上面两个接口

OnGestureListener和OnDoubleTapListener接口里的函数都是强制必须重写的,即使用不到也要重写出来一个空函数但在 SimpleOnGestureListener类的实例或派生类中不必如此,可以根据情况,用到哪个函数就重写哪个函数,因为 SimpleOnGestureListener类本身已经实现了这两个接口的所有函数,只是里面全是空的而已。

拖动状态下拦截touch事件,touch事件的拦截与处理都交给mDraghelper来处理


 /* touch事件的拦截与处理都交给mDraghelper来处理 */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean shouldIntercept = mDragHelper.shouldInterceptTouchEvent(ev);
        boolean moveFlag = moveDetector.onTouchEvent(ev);
        int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_DOWN) {
            // ACTION_DOWN的时候就对view重新排序
            if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_SETTLING) {
                mDragHelper.abort();
            }
            orderViewStack();

            // 保存初次按下时arrowFlagView的Y坐标
            // action_down时就让mDragHelper开始工作,否则有时候导致异常
            mDragHelper.processTouchEvent(ev);
        }

        return shouldIntercept && moveFlag;
    }

    class MoveDetector extends SimpleOnGestureListener {

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx,
            // 拖动了,touch不往下传递
            return Math.abs(dy) + Math.abs(dx) > mTouchSlop;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        try {
            // 统一交给mDragHelper处理,由DragHelperCallback实现拖动效果
            // 该行代码可能会抛异常,正式发布时请将这行代码加上try catch
            mDragHelper.processTouchEvent(e);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return true;
    }

以上代码为事件拦截分发,但整体流程是怎么样的呢?

① setAdapter 调用 doBindAdapter

根据数据不断地addView 添加CardItemView子view,布局动态变化回调函数onLayout重新测量,根据偏移量、步长使子view动态缩放、调整重心调整。

② registerDataSetObserver

Observable是观察者模式的典型应用。在Android下,Observable是一个泛型的抽象类,表示一个观察者对象,提供了观察者注册、反注册及清空三个方法,DataSetObservable在很多的Adapter中都用到,像BaseAdapter。DataSetObservable使用DataSetObserver实例化了Observable。DataSetObserver表示了一个数据集对象的观察者,主要提供了两个方法:

public abstract class DataSetObserver {  

    @Override
    public void onChanged() {  

       xx.offsetLeftAndRight()...
    }  
    @Override
    public void onInvalidated() {  

    }  
}  

onChanged 对View重新排序,执行相关透明动画,如果之前就没有数据,需要保存第一条数据,如果第一条数据不等的话,需要重置弱引用缓存

③ ViewDragHelper . DragHelperCallback

用户手势拖动通过上面的事件拦截交给ViewDragHelper处理,ViewDragHelper拖拽效果的主要逻辑DragHelperCallback

判断当前View是否能拖拽,如果可以请求拦截Touch事件,拖动时上面提到的DataSetObserver.onChange函数(onLayout同理)会调用到offsetLeftAndRight导致viewPosition改变,会调到此处onViewPosChanged,所以onViewPosChanged对index做保护处理,并且此时顶层卡片View位置改变,底层的位置也需要调整

  public void onViewPosChanged(CardItemView changedView) {
        // 调用offsetLeftAndRight导致viewPosition改变,会调到此处,所以此处对index做保护处理
        int index = viewList.indexOf(changedView);
        if (index + 2 > viewList.size()) {
            return;
        }

        processLinkageView(changedView);
    }

   /**
     * 顶层卡片View位置改变,底层的位置需要调整
     *
     * @param changedView 顶层的卡片view
     */
    private void processLinkageView(View changedView) {
        int changeViewLeft = changedView.getLeft();
        int changeViewTop = changedView.getTop();
        int distance = Math.abs(changeViewTop - initCenterViewY)
                + Math.abs(changeViewLeft - initCenterViewX);
        float rate = distance / (float) MAX_SLIDE_DISTANCE_LINKAGE;

        float rate1 = rate;
        float rate2 = rate - 0.1f;

        if (rate > 1) {
            rate1 = 1;
        }

        if (rate2 < 0) {
            rate2 = 0;
        } else if (rate2 > 1) {
            rate2 = 1;
        }

        ajustLinkageViewItem(changedView, rate1, 1);
        ajustLinkageViewItem(changedView, rate2, 2);

        CardItemView bottomCardView = viewList.get(viewList.size() - 1);
        bottomCardView.setAlpha(rate2);
    }

更为详细的说明请阅读源码,有中文注释说明,这个库的作者良心之作啊,满满的中文注释,必须star!!

特别提示:在学习该库的时候一定要建立好模型,有一定ViewDragHelper基础,了解一下“步长”、偏移量等相关知识

CardSwipeLayout


CardSwipeLayout库代码层次比较分明,理解起来也比较容易,实现核心关联类:

RecyclerView.LayoutManager、ItemTouchHelper.Callback

博主对ItemTouchHelper不熟悉,于是乎撸了一篇ItemTouchHelper解析相关博客,访问地址

https://blog.youkuaiyun.com/AnalyzeSystem/article/details/80165740

在你看过这篇文章或者对ItemTouchHelper有了一定的基础认知后,再来看CardSwipeLayout库,感觉 so easy !!!

CardConfig就一些基础变量,OnSwipeListener接口回调定义,核心点在Callback、LayoutManager。

CardLayoutManager .onLayoutChildren()函数根据position动态缩放Item并并调整Item的位置

    @Override
    public void onLayoutChildren(final RecyclerView.Recycler recycler, RecyclerView.State state) {
        detachAndScrapAttachedViews(recycler);
        int itemCount = getItemCount();
        // 当数据源个数大于最大显示数时
        if (itemCount > CardConfig.DEFAULT_SHOW_ITEM) {
            for (int position = CardConfig.DEFAULT_SHOW_ITEM; position >= 0; position--) {
                final View view = recycler.getViewForPosition(position);
                addView(view);
                measureChildWithMargins(view, 0, 0);
                int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
                int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
                // recyclerview 布局
                layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
                        widthSpace / 2 + getDecoratedMeasuredWidth(view),
                        heightSpace / 2 + getDecoratedMeasuredHeight(view));

                if (position == CardConfig.DEFAULT_SHOW_ITEM) {
                    view.setScaleX(1 - (position - 1) * CardConfig.DEFAULT_SCALE);
                    view.setScaleY(1 - (position - 1) * CardConfig.DEFAULT_SCALE);
                    view.setTranslationY((position - 1) * view.getMeasuredHeight() / CardConfig.DEFAULT_TRANSLATE_Y);
                } else if (position > 0) {
                    view.setScaleX(1 - position * CardConfig.DEFAULT_SCALE);
                    view.setScaleY(1 - position * CardConfig.DEFAULT_SCALE);
                    view.setTranslationY(position * view.getMeasuredHeight() / CardConfig.DEFAULT_TRANSLATE_Y);
                } else {
                    view.setOnTouchListener(mOnTouchListener);
                }
            }
        } else {
            // 当数据源个数小于或等于最大显示数时
            for (int position = itemCount - 1; position >= 0; position--) {
                final View view = recycler.getViewForPosition(position);
                addView(view);
                measureChildWithMargins(view, 0, 0);
                int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
                int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
                // recyclerview 布局
                layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 2,
                        widthSpace / 2 + getDecoratedMeasuredWidth(view),
                        heightSpace / 2 + getDecoratedMeasuredHeight(view));

                if (position > 0) {
                    view.setScaleX(1 - position * CardConfig.DEFAULT_SCALE);
                    view.setScaleY(1 - position * CardConfig.DEFAULT_SCALE);
                    view.setTranslationY(position * view.getMeasuredHeight() / CardConfig.DEFAULT_TRANSLATE_Y);
                } else {
                    view.setOnTouchListener(mOnTouchListener);
                }
            }
        }
    }

onChildDraw:在item绘制时调用,主要操作一些属性动画具体实现自行参考源码
滑动移除Item,并通过自定义的Listener回调到主线程

 @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        // 移除 onTouchListener,否则触摸滑动会乱了
        viewHolder.itemView.setOnTouchListener(null);
        int layoutPosition = viewHolder.getLayoutPosition();
        T remove = dataList.remove(layoutPosition);
        adapter.notifyDataSetChanged();
        if (mListener != null) {
            mListener.onSwiped(viewHolder, remove, direction == ItemTouchHelper.LEFT ? CardConfig.SWIPED_LEFT : CardConfig.SWIPED_RIGHT);
        }
        // 当没有数据时回调 mListener
        if (adapter.getItemCount() == 0) {
            if (mListener != null) {
                mListener.onSwipedClear();
            }
        }
    }

看似简单么?错觉而已!!其实还是需要一定的技术功底才能写出来的,只是本篇博客分析的比较粗浅


还有一种卡片实现方案AdapterView的修改,由于目前主流使用RecyclerView系列了,这里就不过多了解了,如果你还想学习可以在下面的学习资料里找到。好吧,博主就是懒不想写了!!博主还有工作需要交接…


学习资料来自 github 开源库
https://github.com/Devlight/InfiniteCycleViewPager
https://github.com/xmuSistone/CardSlidePanel
https://github.com/yuqirong/CardSwipeLayout
https://github.com/mcxtzhang/ZLayoutManager
https://github.com/NateRobinson/CardStackViewpager
https://github.com/xiepeijie/SwipeCardView
https://github.com/flschweiger/SwipeStack
https://github.com/fashare2015/StackLayout
https://github.com/OCNYang/PageTransformerHelp
https://github.com/aohanyao/ViewPagerCardTransformer
https://github.com/zhuchen1109/Swipe-cards
https://github.com/BakerJQ/Android-InfiniteCards
https://github.com/czy1121/turncardlistview


博客
https://www.jianshu.com/p/722ece163629
https://blog.youkuaiyun.com/u012702547/article/details/52334161

CSS background属性深度解析:渲染原理、兼容性与性能优化 background是CSS中看似简单却极为关键的视觉属性,其本质是一套控制图层合成、图像缩放、混合模式与裁剪边界的渲染调度机制。理解background需从基础概念出发:它并非仅设置颜色或图片,而是协调background-image、background-size、background-position、background-clip等多维参数的复合系统;其原理涉及设备像素比(DPR)计算、GPU图层生成逻辑及浏览器合成策略;技术价值体现在精准控制响应式背景、深色模式适配与滚动性能优化;典型应用场景包括 阅读详情

相关推荐

全志H616嵌入式主板硬件设计详解:4K多媒体与工程化实践

嵌入式多媒体系统是边缘计算与智能终端的核心载体,其性能边界由SoC视频硬解能力、高速接口信号完整性及电源管理精度共同决定。全志H616作为ARM Cortex-A53架构的低功耗四核处理器,集成Mali-G31 GPU与专用VPU,原生支持H.265/H.264 4K@60fps硬解,显著降低CPU负载;配合LPDDR4内存子系统与HDMI 2.0a输出通路,构成高能效视频处理链路。在工程实现层面,6层PCB阻抗控制、AXP313A多路动态调压PMIC、XR829 SDIO无线方案等关键技术协同保障系统鲁棒

weixin_33506815的博客 498

关于安卓viewpager实现堆叠卡片交互

可以看到,是一个卡片堆叠的效果,关于这种UI的实现,方法有很多,例如用recyclerview,viewpager,甚至说自定义view都可以实现,本文将讲述如何使用viewpager实现这种效果。简单来讲,就是控制页面的进出场的,简单的你可以用该类实现一些viewpager页面切换进出场的效果,复杂一点的,可以动态计算viewpager滑动过程中,相关view的一个控件属性,等等。这里也不过多叙述了。当position为0的时候,就是当前显示view,同样地-1,就是0的左边,1就是0的右边。

motosheep的博客 3423

汽车级NFC读卡器与CCC数字钥匙:从协议选型到中控台集成实战

NFC作为一种短距离无线通信技术,在汽车数字钥匙领域扮演着保底通道的关键角色。基于ISO 14443A标准,车载NFC读卡器通过电磁感应耦合实现手机虚拟钥匙的识别与认证。在CCC数字钥匙规范下,读卡器不仅需要支持APDU指令集,还必须满足AEC-Q100车规认证和严苛的EMC要求。天线设计是影响读卡距离的核心,需通过线圈尺寸、Q值及匹配网络优化,配合铁氧体隔磁片应对中控台金属环境。应用场景涵盖中控台无钥匙进入、启动授权及安全防护。本文结合实际项目,分享汽车级NFC读卡器从芯片选型、天线调试到整车集成的完整链

weixin_30920513的博客 315

CLRS 第 29.3 节《单纯形算法》习题全解:PIVOT 正确性证明与 SIMPLEX 手算实战

本篇围绕 [docs/Chap29/29.3.md](https://link.gitcode.com/i/0e7c746c094253e2b02f76f77ebe608d) 展开,该文档是《算法导论》(Introduction to Algorithms,第三版)第 29 章"线性规划"第 29.3 节"The simplex algorithm"的习题解答合集(29.3-1 至 29.3-8)

gitblog_00036的博客 451

Android实现卡片堆叠,卡片管理动画效果 (附完整源码)

Android实现卡片堆叠,卡片管理动画效果 (附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 373

Android卡片式轮播

查看效果:https://blog.youkuaiyun.com/lanrenxiaowen/article/details/85019488

【MyAndroid】viewpage+cardView卡片叠层效果展示(2)--100个经典UI设计模板(98/100)

再也不用忧心viewpager动画效果了。 这里使用的是viewpager + cardView组件。全部是原生组件几乎没有自定义组件。 动画效果使用的是viewpager自带的接口类ViewPager.PageTransformer,官方有两个例子也有许多博主解析过原理参考里会有笔者觉得不错的博客访问链接,有兴趣可以看看哈!动画效果有:缩放、移动、透明度设置;单个或多个叠加即可达到动画效果...

产品:SmartApi;服务:大前端++;其他技术分享 1534

ICM42670 IIC驱动与卡尔曼+四元数姿态解算实战

惯性测量单元(IMU)是运动控制、无人机飞控和AR/VR设备的核心传感器,其数据质量直接取决于底层硬件通信可靠性与姿态估计算法鲁棒性。IIC(I²C)作为嵌入式系统中最常用的低速串行总线,需满足确定性时序、抗干扰与实时采样要求;卡尔曼滤波则通过状态建模与噪声协方差优化,在动态环境中融合加速度计与陀螺仪数据;而四元数因其无万向锁、插值平滑、旋转合成高效等优势,成为高精度姿态解算的数学基础。本文以高性能六轴IMU ICM42670为载体,深入剖析IIC硬件设计要点、裸机级驱动优化、Allan方差驱动的卡尔曼参数

weixin_27076351的博客 253

Stack布局技术全解析:原理、实现与优化

Stack布局作为现代UI开发的核心技术,通过Z轴层叠管理实现元素的三维空间排列。其核心原理基于坐标系控制(X/Y/Z轴)和子元素叠加规则,在移动端弹窗、悬浮按钮等场景展现独特优势。跨平台实现上,SwiftUI的ZStack、Android的FrameLayout和Web的position:absolute各有特点,但都遵循相同的层叠逻辑。性能优化需关注复合层数量控制和硬件加速应用,而动态层级管理和交互动画处理则是工程实践中的关键挑战。该技术特别适合实现FAB按钮、卡片叠加等常见UI模式,在React、Fl

weixin_30591519的博客 131

超详细 VMware Horizon 虚拟桌面VDI安装步骤

主要的目的是模拟生产环境中的共享存储。自动桌面相当于共享电脑,大家使用同一个虚拟机,对虚拟机的修改都放在用户的配置文件中,RDS桌面池相当于共享的服务器,可以多人同时连接到服务器上。1:之前已经建立好了NFS的存储,这部分配置好后,以后的虚拟机可以安装到NFS的存储中。2: 使用Composer发布系统可以解决SID,机器名冲突的问题,更重要的可以节约磁盘空间,发布的所有系统可以访问一块磁盘。26: 域选择我们之前建立的域,用户名我输入的是管理员,可以在AD域新建用户点击查找,我这里用的是管理员。

vv12345的博客 1万+

性能测试软件(LR12) 具体汉化(中文)方法

LoadRunner 12 的下载及安装详细过程请参考:https://blog.youkuaiyun.com/xiao66guo/article/details/105465854 1、在LoadRunner文件中找到 Setup.exe 可执行文件,并以管理员的身份运行: C盘 —> Temp—>HP LoadRunner 12.02 Community Edition—> D...

多谢大人光临寒舍,请随便看看,喝口茶吧 ☕️☕️☕️ 1992

Android从零开搞系列:自定义View(14)仿天天美剧拖动卡片的效果(上)

转载请注意:http://blog.youkuaiyun.com/wjzj000/article/details/71597903本菜开源的一个自己写的Demo,希望能给Androider们有所帮助,水平有限,见谅见谅… https://github.com/zhiaixinyang/PersonalCollect (拆解GitHub上的优秀框架于一体,全部拆离不含任何额外的库导入) https://g

Android里的一个彩笔 2245

别让运放自激振荡!手把手教你用波特图分析反相放大电路的稳定性(附LTspice仿真)

本文详细解析了运算放大器在反相放大电路中的稳定性问题,通过波特图分析和LTspice仿真,揭示了自激振荡的成因及解决方案。文章从故障现象识别到数学工具应用,再到实战仿真和工程优化,提供了一套完整的稳定性分析工具链,帮助工程师有效避免运放自激振荡问题。

weixin_31682031的博客 302

BannerViewPager变换器大全:8种酷炫动画效果实战指南

BannerViewPager是一款基于ViewPager2的Android轮播图控件,以其简单高效的特性深受开发者喜爱。本文将为你揭秘8种内置变换器的实现方法,助你轻松打造令人惊艳的轮播效果。无论是深度缩放、立体旋转还是折叠动画,都能通过简单配置让你的App界面瞬间提升质感! ## 变换器基础:一分钟上手 BannerViewPager的变换器系统采用工厂模式设计,所有动画效果都通过`Pag

gitblog_00973的博客 661

机器学习预测股票收益(一)之随机森林模型

机器学习预测股票收益(一)前言一、导入库和数据二、处理数据以及计算特征变量三、使用随机森林回归预测股票收益1.构建训练集和测试集2.查看预测结果四、根据预测结果构建long-short投资组合1.定义投资组合函数2.定义绩效分析函数五、引入Fama-French Factor六、投资组合表现1.超额收益表现2.多因子回归总结 前言 本文将使用Python整理1927-2020年所有美国上市公司股票数据。根据历史收益以及交易量,使用随机森林,支持向量机以及神经网络等机器学习方法预测股票收益。最优结果构建的资产

weixin_47174968的博客 1万+

ollama如何在自己的服务器上跑Qwen3(小白必看)

在国内下载ollama最新安装包时,使用curl -fsSL https://ollama.com/install.sh | sh命令可能会遇到网络问题导致下载进度停滞。为了解决这一问题,可以通过国内的镜像源进行下载,例如使用modelscope社区提供的最新ollama镜像仓库。具体步骤包括:首先通过pip install modelscope安装modelscope,然后使用modelscope download命令下载ollama-linux镜像,接着进入下载目录并赋予安装脚本执行权限,最后运行安装脚

Ven%的博客 756

【用案例学Jetpack ComposeUI设计】第2课 布局进阶

本课深入解析Compose布局核心,通过7个真实案例揭示布局三阶段(测量、决定尺寸、放置)与Modifier顺序的深层影响。从点击区域控制到响应式布局,涵盖IntrinsicSize、ConstraintLayout、SubcomposeLayout等高级技术,结合逐行注释代码与设计解读,帮助开发者精准掌控UI。

jackchuanqi的博客 223

高斯过程的数学理解

G澳大利亚的过程是有益的,特别是当我们有少量数据时。当我在制造业担任数据科学家时,我们的团队使用这种算法来揭示我们接下来应该进行哪些实验条件。但是,此算法不如其他算法流行。在这篇博客中,我将通过可视化和 Python 实现来解释高斯过程 [1] 的数学背景。

gongdiwudu的专栏 3606

基于HarmonyOS API 24,React Native鸿蒙跨平台响应式统计可以采用@Watch装饰器实现,依赖数组[messages]指定了效果触发的条件,避免了不必要的计算开销

虽然类的调用签名相当严格,但 Python 并不强制要求返回参数的类型。and eval in Python(参见 http://lucumr.pocoo.org/2011/2/1/exec-in-python/)。”换句话说,即使你有一丝的怀疑,也不应该使用它们,而应该尝试寻找其他解决方法。• exec(object, globals, locals):这一函数允许你动态执行 Python 代码。对于元编程而言,最有用的显然是 exec(),因为它可以执行任意 Python 语句的序列。

2401_86113894的博客 338

〔重庆理工大学〕计算机组成原理课设报告--16位单周期CPU设计

本课程设计的实验平台为Altera Quartus II 软件和Altera Cyclone V Starter 工具箱。(1)Cyclone V是Altera FPGAs家族的一类,它面向低功耗应用。Cyclone V GX 5CGXFC5C6F27C7N 芯片有不同的转换器,按钮,LED灯,七段显示器,HDMI接口,SD卡读卡器以及其他链接等。Cyclone V GX 5CGXFC5C6F27C7N是Starter工具箱的重要组件。(2)测试台包含在测设备(DUT)和用于仿真的模拟输入。

Pretty Boy Fox的博客 1066

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

React Native鸿蒙HarmonyOS API 24 使用FoodDetailModal采用条件渲染的覆盖层(absolute + 半透明背景)来模拟弹窗

描述符的一个示例用法就是将类属性的初始化延迟到被实例访问时。如果这些属性的初始化依赖全局应用上下文的话,那么这一点可能有用。另一个使用场景是初始化的代价很大,但在导入类的时候不知道是否会用到这个属性。这样的描述符可以按照如下所示来实现:defdef’)else:’)下面是示例用法:m.lazily_m.lazilycached!

2401_86113894的博客 736

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

基于HarmonyOS API 24实战解析构建钓鱼战记记录应用在 ArkTS 的响应式系统中,数组的操作(push、pop、splice 等)同样会被追踪

在移动互联网与智能穿戴设备高度普及的今天,"习惯养成"已经从一个模糊的自我管理理念,演变为一个可量化、可追踪、可视化的数字化产品赛道。越来越多的人希望借助手中的智能终端,把"早起、冥想、阅读、运动"这些抽象的自律行为,转化为一条条清晰的数据曲线和一张张可触摸的打卡卡片。而鸿蒙生态(HarmonyOS)凭借其跨设备协同、分布式软总线以及声明式 UI 开发框架 ArkUI,为这类注重"轻量化交互 + 即时反馈"的生活方式类应用提供了极为理想的生长土壤。本应用正是一款面向"晨间场景"深度打磨的习惯追踪工具。它聚焦

2301_79516720的博客 212

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Shotcut 动画效果问题清单:转场生硬、关键帧做不溜、预览卡顿,逐一给解法

Shotcut 是一款基于 Qt 和 MLT 框架的开源视频编辑器(GPLv3)。这篇文章按"问题—解法"的方式,覆盖淡入淡出、关键帧设置、插值选择、预览卡顿与动画复用五类常见坑,所有操作都基于界面功能,不涉及外部依赖。 ## 问题一:切镜头太硬,淡入淡出做得像"闪了一下" 很多人做淡入淡出会直接拉 Opacity 滤镜,结果过渡只有一两帧,看起来像闪帧。其实 Shotcut 里做"软切"有三

gitblog_00174的博客 923

数据可视化设计的底层逻辑:从视觉语法到决策表达

数据可视化不是图表绘制技术,而是以人类视觉认知规律为基础的信息编码科学。其核心在于将抽象数据转化为可被快速识别、准确比较、可靠决策的视觉信号——这涉及数据-墨水比优化、任务驱动的图表选型、视觉通道优先级控制等关键原理。在实际工程中,它直接决定业务方能否在3秒内抓住关键偏差、是否因坐标轴截断产生误判、能否跨部门对齐指标语义。尤其在报表交付、大屏监控、跨团队协同等高频场景下,一套可复用的视觉语法体系(如颜色系统规范、问题卡片机制、无障碍验证流程)已成为数据产品可信落地的技术刚需。

Ferrerooo 成长 405

别只当它是 JS 加了类型:TypeScript 类型系统与编译器原理全解

写了一两年 TypeScript,你大概也遇到过这种场面:同事把接口字段从 `string` 改成 `string | null`,下游十来个组件没有任何报错,直到用户投诉"偶发白屏"才发现问题;或者你在 `switch` 里漏了一个分支,编译器一声不吭,因为 `default` 兜底了。这些坑的根源都不是语法不熟,而是没把类型系统当成一套可以推理、可以钉死边界的工具。这篇文章把 TypeScri

gitblog_00516的博客 190

蓝牙4.2+NFC二合一模组实战:从天线匹配到安全防护

短距离无线通信中,蓝牙与NFC各司其职:蓝牙适合持续连接,NFC擅长“碰一碰”交互。将蓝牙4.2和NFC集成于同一模组,可解决传统蓝牙配对繁琐的痛点,通过Tap-to-Pair实现手机触碰即连。本文从协议层对比ISO14443A与15693,剖析NFC天线LC谐振匹配与PCB/FPC选型,并结合音乐墙、快速配网等场景演示NDEF标签的读写技巧。同时深入探讨NFC中继攻击原理与距离约束、RSSI检测等防御思路,为低功耗物联网产品提供从硬件调试到安全设计的完整参考。

weixin_34208185的博客 313
上一篇: Android开发之ItemTouchHelper解析
下一篇: 摄影后期从入门到精通(一)
AnalyzeSystem
博客等级 码龄11年 204粉丝 114原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值