ViewDragHelper实战 自己打造Drawerlayout

2023-11-07 18:38

本文主要是介绍ViewDragHelper实战 自己打造Drawerlayout,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

       

转载请标明出处:
  http://blog.csdn.net/lmj623565791/article/details/47396187;
  本文出自:【张鸿洋的博客】

一、概述

中间拖了蛮长时间了,在上一篇我们介绍了ViewDragHelper,详情:ViewDragHelper完全解析,当然了,上一篇都是小示例的形式去演示代码功能,并不能给人一种实用的感觉。那么,本篇博客就准备实用ViewDragHelper来实现一个DrawerLayout的效果,当然了,大家也可以选择直接去看Drawerlayout的源码。相信侧滑大家肯定不陌生,网络上流传无数个版本,其实利用ViewDragHelper就能方便的写出比较不错的侧滑代码~

那么首先上个效果图:

ok,其实和DrawerLayout效果类似,当然不是完全的一致~~本篇的主要目的也是演示VDH的实战用法,大家在选择侧滑的时候还是建议使用DrawerLayout.

二、实战

(一)布局文件

首先看一下布局文件:

<com.zhy.learn.view.LeftDrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"                                   android:layout_width="match_parent"android:id="@+id/id_drawerlayout"                                     android:layout_height="match_parent"    >    <!--content-->    <RelativeLayout        android:clickable="true"        android:layout_width="match_parent"        android:background="#44ff0000"        android:layout_height="match_parent">        <TextView            android:id="@+id/id_content_tv"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="hello world"            android:textSize="40sp"            android:layout_centerInParent="true"/>    </RelativeLayout>    <!--menu-->    <FrameLayout        android:id="@+id/id_container_menu"        android:layout_width="match_parent"        android:layout_height="match_parent"        >    </FrameLayout></com.zhy.learn.view.LeftDrawerLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

ok,可以看到我们的LeftDrawerLayout里面一个是content,一个是menu~为了方便,我们就默认child0为content,child1为menu。

(二)LeftDrawerLayout
package com.zhy.learn.view;import android.content.Context;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import com.zhy.util.common.L;/** * Created by zhy on 15/5/29. */public class LeftDrawerLayout extends ViewGroup{    private static final int MIN_DRAWER_MARGIN = 64; // dp    /**     * Minimum velocity that will be detected as a fling     */    private static final int MIN_FLING_VELOCITY = 400; // dips per second    /**     * drawer离父容器右边的最小外边距     */    private int mMinDrawerMargin;    private View mLeftMenuView;    private View mContentView;    private ViewDragHelper mHelper;    /**     * drawer显示出来的占自身的百分比     */    private float mLeftMenuOnScrren;    public LeftDrawerLayout(Context context, AttributeSet attrs)    {        super(context, attrs);        //setup drawer's minMargin        final float density = getResources().getDisplayMetrics().density;        final float minVel = MIN_FLING_VELOCITY * density;        mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);        mHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback()        {            @Override            public int clampViewPositionHorizontal(View child, int left, int dx)            {                int newLeft = Math.max(-child.getWidth(), Math.min(left, 0));                return newLeft;            }            @Override            public boolean tryCaptureView(View child, int pointerId)            {                L.e("tryCaptureView");                return child == mLeftMenuView;            }            @Override            public void onEdgeDragStarted(int edgeFlags, int pointerId)            {                L.e("onEdgeDragStarted");                mHelper.captureChildView(mLeftMenuView, pointerId);            }            @Override            public void onViewReleased(View releasedChild, float xvel, float yvel)            {                L.e("onViewReleased");                final int childWidth = releasedChild.getWidth();                float offset = (childWidth + releasedChild.getLeft()) * 1.0f / childWidth;                mHelper.settleCapturedViewAt(xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -childWidth, releasedChild.getTop());                invalidate();            }            @Override            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy)            {                final int childWidth = changedView.getWidth();                float offset = (float) (childWidth + left) / childWidth;                mLeftMenuOnScrren = offset;                //offset can callback here                 changedView.setVisibility(offset == 0 ? View.INVISIBLE : View.VISIBLE);                invalidate();            }            @Override            public int getViewHorizontalDragRange(View child)            {                return mLeftMenuView == child ? child.getWidth() : 0;            }        });        //设置edge_left track        mHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);        //设置minVelocity        mHelper.setMinVelocity(minVel);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)    {        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        setMeasuredDimension(widthSize, heightSize);        View leftMenuView = getChildAt(1);        MarginLayoutParams lp = (MarginLayoutParams)                leftMenuView.getLayoutParams();        final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,                mMinDrawerMargin + lp.leftMargin + lp.rightMargin,                lp.width);        final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,                lp.topMargin + lp.bottomMargin,                lp.height);        leftMenuView.measure(drawerWidthSpec, drawerHeightSpec);        View contentView = getChildAt(0);        lp = (MarginLayoutParams) contentView.getLayoutParams();        final int contentWidthSpec = MeasureSpec.makeMeasureSpec(                widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);        final int contentHeightSpec = MeasureSpec.makeMeasureSpec(                heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);        contentView.measure(contentWidthSpec, contentHeightSpec);        mLeftMenuView = leftMenuView;        mContentView = contentView;    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b)    {        View menuView = mLeftMenuView;        View contentView = mContentView;        MarginLayoutParams lp = (MarginLayoutParams) contentView.getLayoutParams();        contentView.layout(lp.leftMargin, lp.topMargin,                lp.leftMargin + contentView.getMeasuredWidth(),                lp.topMargin + contentView.getMeasuredHeight());        lp = (MarginLayoutParams) menuView.getLayoutParams();        final int menuWidth = menuView.getMeasuredWidth();        int childLeft = -menuWidth + (int) (menuWidth * mLeftMenuOnScrren);        menuView.layout(childLeft, lp.topMargin, childLeft + menuWidth,                lp.topMargin + menuView.getMeasuredHeight());    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev)    {        boolean shouldInterceptTouchEvent = mHelper.shouldInterceptTouchEvent(ev);        return shouldInterceptTouchEvent;    }    @Override    public boolean onTouchEvent(MotionEvent event)    {        mHelper.processTouchEvent(event);        return true;    }    @Override    public void computeScroll()    {        if (mHelper.continueSettling(true))        {            invalidate();        }    }    public void closeDrawer()    {        View menuView = mLeftMenuView;        mLeftMenuOnScrren = 0.f;        mHelper.smoothSlideViewTo(menuView, -menuView.getWidth(), menuView.getTop());    }    public void openDrawer()    {        View menuView = mLeftMenuView;        mLeftMenuOnScrren = 1.0f;        mHelper.smoothSlideViewTo(menuView, 0, menuView.getTop());    }    @Override    protected LayoutParams generateDefaultLayoutParams()    {        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);    }    public LayoutParams generateLayoutParams(AttributeSet attrs)    {        return new MarginLayoutParams(getContext(), attrs);    }    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p)    {        return new MarginLayoutParams(p);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212

哈,很少的代码就完成了我们的侧滑的编写,目测如果使用横向的LinearLayout代码更短。构造方法中,主要就是初始化我们的mDragHelper了,接下来onMeasure和onLayout都比较简单,onLayout也只是去将我们的menu设置到屏幕的左侧以至于不可见。onInterceptTouchEventonTouchEvent中都只需要简单的调用mDragHelper的方法。那么核心代码都在我们的ViewDragHelper.Callback的实例中了。注意一点:我们LeftDrawerLayout默认的LayoutParams为MarginLayoutParams,注意复写相关方法。

接下来就把注意力放到我们的Callback中,我尽可能的按照调用的逻辑来解释各个方法:

  • onEdgeDragStarted 如果你仔细的看过上篇,那么一定知道这个方法的回调位置;因为我们的View不可见,所以我们没有办法直接通过触摸到它来把menu设置为captureView,所以我们只能设置边界检测,当MOVE时回调onEdgeDragStarted时,我们直接通过captureChildView手动捕获。

  • tryCaptureView 那么既然我们手动捕获了,为什么还需要这个方法呢?主要是因为当Drawer拉出的时候,我们通过拖拽Drawer也能进行移动菜单。

  • clampViewPositionHorizontal 主要是移动的时候去控制控制范围,可以看到我们的int newLeft = Math.max(-child.getWidth(), Math.min(left, 0));一定>=-child.getWidth() && <=0 。

  • getViewHorizontalDragRange 为什么要复写,我们上篇已经描述过,返回captureView的移动范围。

  • onViewReleased 则是释放的时候触发的,我们计算当前显示的百分比,以及加速度来决定是否显示drawer,从代码可以看出,当xvel > 0 || xvel == 0 && offset > 0.5f显示我们的菜单,其他情况隐藏。这里注意一点xvel的值只有大于我们设置的minVelocity才会出现大于0,如果小于我们设置的值则一直是0。

  • onViewPositionChanged 整个pos变化的过程中,我们计算offset保存,这里可以使用接口将offset回调出去,方便做动画。

ok,我们重写的所有方法描述完成了~那么博文主要内容也就结束了~哈~是不是 so easy ~!

呃,忘了MainActivity和Fragment的代码了~~按顺序贴

(三)LeftDrawerLayoutActivity
package com.imooc.testandroid;import android.os.Bundle;import android.support.v4.app.FragmentManager;import android.support.v7.app.ActionBarActivity;import android.view.Menu;import android.view.MenuItem;import android.widget.TextView;import com.zhy.learn.view.LeftDrawerLayout;public class LeftDrawerLayoutActivity extends ActionBarActivity{    private LeftMenuFragment mMenuFragment;    private LeftDrawerLayout mLeftDrawerLayout ;    private TextView mContentTv ;    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_left_drawer_layout);        mLeftDrawerLayout = (LeftDrawerLayout) findViewById(R.id.id_drawerlayout);        mContentTv = (TextView) findViewById(R.id.id_content_tv);        FragmentManager fm = getSupportFragmentManager();        mMenuFragment = (LeftMenuFragment) fm.findFragmentById(R.id.id_container_menu);        if (mMenuFragment == null)        {            fm.beginTransaction().add(R.id.id_container_menu, mMenuFragment = new LeftMenuFragment()).commit();        }        mMenuFragment.setOnMenuItemSelectedListener(new LeftMenuFragment.OnMenuItemSelectedListener()        {            @Override            public void menuItemSelected(String title)            {                mLeftDrawerLayout.closeDrawer();                mContentTv.setText(title);            }        });    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

可以看到drawer使用了一个Fragment ~~

(四) LeftMenuFragment
import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.ListFragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ListView;/** * Created by zhy on 15/4/26. */public class LeftMenuFragment extends ListFragment {    private static final int SIZE_MENU_ITEM = 3;    private MenuItem[] mItems = new MenuItem[SIZE_MENU_ITEM];    private LeftMenuAdapter mAdapter;    private LayoutInflater mInflater;    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mInflater = LayoutInflater.from(getActivity());        MenuItem menuItem = null;        for (int i = 0; i < SIZE_MENU_ITEM; i++) {            menuItem = new MenuItem(getResources().getStringArray(R.array.array_left_menu)[i], false, R.drawable.music_36px, R.drawable.music_36px_light);            mItems[i] = menuItem;        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        return super.onCreateView(inflater, container, savedInstanceState);    }    @Override    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        view.setBackgroundColor(0xffffffff);        setListAdapter(mAdapter = new LeftMenuAdapter(getActivity(), mItems));    }    @Override    public void onListItemClick(ListView l, View v, int position, long id) {        super.onListItemClick(l, v, position, id);        if (mMenuItemSelectedListener != null) {            mMenuItemSelectedListener.menuItemSelected(((MenuItem) getListAdapter().getItem(position)).text);        }        mAdapter.setSelected(position);    }    //选择回调的接口    public interface OnMenuItemSelectedListener {        void menuItemSelected(String title);    }    private OnMenuItemSelectedListener mMenuItemSelectedListener;    public void setOnMenuItemSelectedListener(OnMenuItemSelectedListener menuItemSelectedListener) {        this.mMenuItemSelectedListener = menuItemSelectedListener;    }}public class MenuItem{    public MenuItem(String text, boolean isSelected, int icon, int iconSelected) {        this.text = text;        this.isSelected = isSelected;        this.icon = icon;        this.iconSelected = iconSelected;    }    boolean isSelected;    String text;    int icon;    int iconSelected;}/** * Created by zhy on 15/4/26. */public class LeftMenuAdapter extends ArrayAdapter<MenuItem> {    private LayoutInflater mInflater;    private int mSelected;    public LeftMenuAdapter(Context context, MenuItem[] objects) {        super(context, -1, objects);        mInflater = LayoutInflater.from(context);    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        if (convertView == null) {            convertView = mInflater.inflate(R.layout.item_left_menu, parent, false);        }        ImageView iv = (ImageView) convertView.findViewById(R.id.id_item_icon);        TextView title = (TextView) convertView.findViewById(R.id.id_item_title);        title.setText(getItem(position).text);        iv.setImageResource(getItem(position).icon);        convertView.setBackgroundColor(Color.TRANSPARENT);        if (position == mSelected) {            iv.setImageResource(getItem(position).iconSelected);            convertView.setBackgroundColor(getContext().getResources().getColor(R.color.state_menu_item_selected));        }        return convertView;    }    public void setSelected(int position) {        this.mSelected = position;        notifyDataSetChanged();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141

贴了一大串,主要就是Fragment的代码,内部有个ListView,所以还有个Adapter,这个Fragment在之前的博文中出现过,搬过来而已。item的布局文件就是一个TextView和ImageView~~不贴了~~大家自己下载源码~

源码点击下载(导入方式注意看下ReadMe)

ok,到此结束~~hava a nice day ~~


欢迎关注我的微博:
http://weibo.com/u/3165018720


群号:463081660,欢迎入群

   

微信公众号:hongyangAndroid
  (欢迎关注,第一时间推送博文信息)
 

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述

这篇关于ViewDragHelper实战 自己打造Drawerlayout的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/365537

相关文章

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Java Web实现类似Excel表格锁定功能实战教程

《JavaWeb实现类似Excel表格锁定功能实战教程》本文将详细介绍通过创建特定div元素并利用CSS布局和JavaScript事件监听来实现类似Excel的锁定行和列效果的方法,感兴趣的朋友跟随... 目录1. 模拟Excel表格锁定功能2. 创建3个div元素实现表格锁定2.1 div元素布局设计2.

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

CSS3打造的现代交互式登录界面详细实现过程

《CSS3打造的现代交互式登录界面详细实现过程》本文介绍CSS3和jQuery在登录界面设计中的应用,涵盖动画、选择器、自定义字体及盒模型技术,提升界面美观与交互性,同时优化性能和可访问性,感兴趣的朋... 目录1. css3用户登录界面设计概述1.1 用户界面设计的重要性1.2 CSS3的新特性与优势1.