QQ est un outil de chat dont tout le monde ne peut pas se passer. Il est à la fois pratique et pratique. Depuis la mise à jour de QQ vers la version 6.0, le panneau principal de glissement latéral a été réduit de l'original à gauche et à droite, ce qui est lisse. a grandement amélioré l'apparence, j'ai donc essayé de comprendre les différentes logiques à l'intérieur, combinées avec des informations pertinentes, et fait des recherches.
Nous savons que l'une des classes principales ici est ViewDragHelper, nous devons donc d'abord comprendre cette classe ViewDragHelper. Comme le dit le proverbe, nous allons frapper le serpent avec sept pouces. Le document officiel le présente. Qu'y a-t-il de caractéristiques étranges ?
Premier héritage :
java.lang.Object
android.support.v4.widget.ViewDragHelper
La classe parent directe est Object.
Présentation de la classe
ViewDragHelper est une classe utilitaire permettant d'écrire des ViewGroups personnalisés. Elle offre un certain nombre d'opérations utiles et de suivi d'état pour permettre à un utilisateur de faire glisser et de repositionner des vues dans son ViewGroup parent.
Il s'agit d'une classe d'outils pour écrire des ViewGroup personnalisés. Cette province fournit de nombreuses méthodes et états utiles pour permettre aux utilisateurs de faire glisser et de dessiner leurs trajectoires et positions dans le ViewGroup parent.
Classes imbriquées (classes imbriquées)
ViewDragHelper.Callback
Un rappel est utilisé comme canal de communication avec le ViewDragHelper vers la vue parent qui l'utilise.
Un rappel est utilisé comme interface de communication entre ViewDragHelper et sa vue parent
Une méthode statique publique :
Nous peut savoir que ViewDragHelper est construit via la méthode create(). Ceci sera introduit en détail ultérieurement.
Jetons un coup d'œil à quelques méthodes qui doivent être utilisées :
public boolean tryCaptureView(View child, int pointerId) {} public int getViewHorizontalDragRange(View child) {} public int clampViewPositionHorizontal(View child, int left, int dx) {} public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {} public void onViewReleased(View releasedChild, float xvel, float yvel) {}
Les méthodes ci-dessus auront des commentaires détaillés dans le code, il suffit de les regarder ici. Ensuite, nous avons besoin pour réécrire la méthode
D'accord, cela dit, commençons par une méthode simple qui peut réaliser le glissement (je crois que lorsque vos deux vues peuvent être déplacées, à un moment donné, vous trouverez, oh , c'est si simple en quelques étapes seulement) :
La première étape consiste à implémenter la fonction glisser-déposer (implémentez-la en 3 étapes simples)
//1、通过静态方法初始化操作 mDragHelper = ViewDragHelper.create(this, mCallback); /** * 2、传递触摸事件 * * @param ev * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { //让自己的控件自行判断是否去拦截 return mDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { try { //自己去处理触摸事件 mDragHelper.processTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } //返回true,这样才能持续接收,要不然我们不会传递而是被拦截了 return true; } ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() { /** * 根据返回结果决定当前child是否可以拖拽 * 尝试捕获的时候调用,如果返回的是主面板,那么负面版是不能被调用的 * @param child 当前被拖拽的view * @param pointerId 区分多点触摸的id * @return 返回true 是都可以拖拽 * 返回child == mLeftContent 左侧可以移动 * 返回child == mMainContent 右侧可以移动 */ @Override public boolean tryCaptureView(View child, int pointerId) { //这里要返回true,要不然不能拖拽 return true; } /** * 根据建议值修正将要移动的位置 此时并没有发生真正的移动(左右) * * @param child 当前拖拽的view * @param left 新的位置的建议值 oldLeft + dx * @param dx 变化量 和变化之前位置的差值 * @return */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { //返回的拖拽的范围,不对拖拽进行真正的限制,仅仅决定了动画执行的速度 return left; } };
D'accord, le premier rendu Il peut sortir, c'est-à-dire qu'il peut être glissé et déposé. Est-ce très simple à réaliser :
Mais si vous soumettez la tâche comme ceci, vous ne voulez pas. travailler ? D'accord, d'accord, contrôlons la position de glissement pour qu'il ne puisse pas glisser au hasard. ,
La deuxième étape consiste à contrôler la plage de traînée
Nous voulons contrôler la plage de traînée. Nous devons d'abord obtenir ces deux contrôles et obtenir les propriétés de ces deux contrôles. nous opérons. Nous avons donc réécrit la méthode :
/** * Finalize inflating a view from XML. This is called as the last phase * of inflation, after all child views have been added. * 当xml填充完的时候去掉用,在这里我们可以找到我们要去操控的那两个布局 * <p>Even if the subclass overrides onFinishInflate, they should always be * sure to call the super method, so that we get called. */ @Override protected void onFinishInflate() { super.onFinishInflate(); /** * 根据索引来找 */ /** * 得到左边的布局 */ mLeftContent = (ViewGroup) getChildAt(0); /** * 得到主main布局 */ mMainContent = (ViewGroup) getChildAt(1); }
Ensuite, nous devons obtenir la largeur et la hauteur. Nous savons qu'elles peuvent être obtenues dans onMessure(), mais après vérification, la méthode suivante est également What can be. obtenu :
/** * 当尺寸变化的时候去调用 * This is called during layout when the size of this view has changed * @param w * @param h * @param oldw * @param oldh */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); /** * 屏幕的宽度和高度 */ mHeight = getMeasuredHeight(); mWidth = getMeasuredWidth(); /** * 自定义左侧view拖拽出来的距离 */ mRange = (int) (mWidth * 0.7); }
D'accord, nous avons obtenu la largeur, la hauteur et la distance de traînée dont nous avons besoin, nous allons donc les limiter ensuite.
Il suffit d'ajouter ceci à la méthode clampViewPositionHorizontal() pour empêcher le panneau principal de se déplacer vers la gauche, et le panneau de gauche ne peut se déplacer que vers la position mRange à droite. (Vous pouvez l'essayer ici)
if (child == mMainContent) { left = fixLeft(left); } /** * 修正方法 * 根据范围去修正左侧的view的可见 * * @param left * @return */ private int fixLeft(int left) { if (left < 0) { return 0; } else if (left > mRange) { return mRange; } return left; }
À l'heure actuelle, notre aperçu de base est sorti, mais il y a toujours un problème, c'est-à-dire que nous avons obtenu l'effet de glissement (celui de droite C'est décidé, mais quand on fait glisser le LeftView, on peut toujours le faire glisser vers la droite) Il faut trouver un moyen de le limiter, c'est-à-dire le limiter. Je ne peux faire glisser la vue de gauche à droite que par le. distance de mRange. À ce moment, nous devons vérifier la méthode. Quelle méthode peut obtenir la valeur de la position modifiée, puis la modifier :
/** * 当view位置改变的时候,处理要做的事情,更新状态,伴随动画,重绘界面 * * 此时view已经发生了位置的改变 * * @param changedView 改变的位置view * @param left 新的左边值 * @param top * @param dx 水平变化量 * @param dy */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); int newLeft = left; //如果我们拖拽的是左面板 if (changedView == mLeftContent) { //新的左侧位置是我们的主面板的左侧加上水平变化量 newLeft = mMainContent.getLeft() + dx; } //进行修正(不能超出我们的规定的范围) newLeft = fixLeft(newLeft); if (changedView == mLeftContent) { //当左面板移动之后,在强制放回去 mLeftContent.layout(0, 0, 0 + mWidth, 0 + mHeight); mMainContent.layout(newLeft, 0, newLeft + mWidth, 0 + mHeight); } //兼容低版本 强制重绘 invalidate(); }
D'accord, à ce moment, notre effet général est sorti. , jetons un œil au rendu. (La couleur blanche au milieu ici est un problème d'enregistrement, et il n'y a aucun problème lors des tests personnels)
À ce stade, un glisser-déposer approximatif peut être réalisé. Bien sûr, ma mise en page actuelle est simple. implémentation ci-dessous (vous devez d'abord ajouter quelques contrôles, ajoutez-les simplement vous-même aux deux LinearLayouts)
<?xml version="1.0" encoding="utf-8"?> <com.example.qqsliding.DragLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.qqsliding.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@mipmap/sidebar_bg"> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="#0CB8F6" android:gravity="center_vertical"> <ImageView android:layout_width="30dp" android:layout_height="30dp" android:layout_marginLeft="15dp" android:src="@mipmap/icon_avatar_white"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:text="Header"/> <ImageView android:layout_width="30dp" android:layout_height="30dp" android:layout_alignParentRight="true" android:layout_marginRight="15dp" android:src="@mipmap/icon_search"/> </RelativeLayout> </LinearLayout> </com.example.qqsliding.DragLayout>
Mais ceux qui font attention peuvent constater que lorsque nous glissons et déposons, c'est particulièrement rigide. car nous n'avons pas ajouté d'animation. L'effet est simplement traîné. Pour ajouter des animations spécifiques et définir des effets de rappel, veuillez lire cet article pour apprendre l'optimisation du glissement Android avec le menu coulissant latéral QQ6.0 (2). être utile à tout le monde.
Pour en savoir plus sur Android utilisant ViewDragHelper pour implémenter une interface coulissante latérale de type QQ6.0 (1), veuillez faire attention au site Web PHP chinois pour les articles connexes !