Maison > Java > javaDidacticiel > le corps du texte

Android utilise ViewDragHelper pour implémenter la dernière version de l'exemple de code d'effet d'interface coulissante latérale QQ6.X

高洛峰
Libérer: 2017-01-13 10:29:56
original
1281 Les gens l'ont consulté

(1). Avant-propos :

QQ a subi une mise à jour majeure au cours des deux derniers jours (6. Certaines modifications ont été apportées, nous allons donc aujourd'hui imiter et implémenter l'effet d'interface coulissante du Version QQ6.X. Aujourd'hui, nous utilisons toujours l'artefact ViewDragHelper pour l'implémenter

Le code spécifique de cet exemple a été téléchargé dans le projet ci-dessous. Vous êtes invités à le mettre en vedette et à le créer.

https://github.com/jiangqqlmj/DragHelper4QQ
Adresse du projet-cadre FastDev4Android : https://github.com/jiangqqlmj/FastDev4Android

(二).Utilisation de base de ViewGragHelper

Plus tôt, nous avons appris l'utilisation de base de ViewGragHelper et connaissions également l'utilisation de plusieurs méthodes à l'intérieur. Nous allons maintenant passer en revue les étapes d'utilisation de base. Les étapes pour utiliser ViewGragHelper pour implémenter le mouvement glisser-déposer des sous-vues sont les suivantes :

Créer une instance de ViewGragHelper (passer dans le rappel)

Réécrire le traitement d'interception d'événement méthodes onInterceptTouch et onTouchEvent

Implement Callback, implémentez les méthodes associées tryCaptureView et la méthode de distance de mouvement horizontale ou verticale

Pour une analyse plus détaillée, vous pouvez lire le blog précédent, ou nous passerons l'analyse détaillée ici aujourd'hui. Expliquez avec des exemples.

(3).Analyse sur la mise en œuvre de l'effet de dérapage dans QQ5>

En observant ce qui précède, nous pouvons le comprendre comme deux vues, l'une est la vue de fonction inférieure à gauche et la vue du bas. other est la vue du contenu de la fonction principale supérieure. Lorsque nous faisons glisser la vue supérieure ou la diapositive vers la gauche et la droite, les diapositives de la vue supérieure et inférieure et la taille de la vue changent en conséquence et des animations pertinentes sont ajoutées. Bien sûr, nous pouvons cliquer sur la vue supérieure pour ouvrir ou fermer le menu coulissant latéral.

(4). Implémentation de composants personnalisés de l'effet de glissement latéralAndroid utilise ViewDragHelper pour implémenter la dernière version de lexemple de code deffet dinterface coulissante latérale QQ6.X

1 Tout d'abord, nous intégrons FrameLayout pour créer un View DragLayout personnalisé. Certaines variables définies en interne sont les suivantes (incluant principalement certaines classes de configuration, gestes, instances ViewDragHelper, largeur et hauteur de l'écran, déplacement des sous-vues View, etc.)


Ensuite, une interface de rappel est également définie en interne Handle. quelques rappels d'événements d'ouverture, de fermeture et de glissement de page pendant le processus de glissement :

2. Commencez à créer une instance de ViewDragHelper, en la créant toujours lorsque le View DragLayout personnalisé est initialisé, en utilisant la méthode statique de ViewGragHelper :

//是否带有阴影效果 
private boolean isShowShadow = true; 
//手势处理类 
private GestureDetectorCompat gestureDetector; 
//视图拖拽移动帮助类 
private ViewDragHelper dragHelper; 
//滑动监听器 
private DragListener dragListener; 
//水平拖拽的距离 
private int range; 
//宽度 
private int width; 
//高度 
private int height; 
//main视图距离在ViewGroup距离左边的距离 
private int mainLeft; 
private Context context; 
private ImageView iv_shadow; 
//左侧布局 
private RelativeLayout vg_left; 
//右侧(主界面布局) 
private CustomRelativeLayout vg_main;
Copier après la connexion

Lorsque la méthode create() est créée, une classe de rappel dragHelperCallBack est transmise, qui sera abordée dans le quatrième point.

/** 
* 滑动相关回调接口 
*/
public interface DragListener { 
//界面打开 
public void onOpen(); 
//界面关闭 
public void onClose(); 
//界面滑动过程中 
public void onDrag(float percent); 
}
Copier après la connexion

3. Ensuite, vous devez réécrire la méthode d'événement dans ViewGroup, intercepter l'événement tactile et le traiter en interne dans ViewGragHelper, afin d'atteindre l'objectif de glisser et de déplacer la sous-vue <🎜 ; >

public DragLayout(Context context,AttributeSet attrs, int defStyle) { 
super(context, attrs, defStyle); 
gestureDetector = new GestureDetectorCompat(context, new YScrollDetector()); 
dragHelper =ViewDragHelper.create(this, dragHelperCallback); 
}
Copier après la connexion
Ceci, nous l'interceptons dans onInterceptTouchEvent pour transférer l'événement du contrôle parent vers la vue enfant, puis l'interceptons dans la méthode onTouchEvent pour permettre à ViewDragHelper d'effectuer le traitement de la consommation.


4. Commencez à personnaliser la création d'une instance de ViewDragHelper.Callback, dragHelperCallback implémente respectivement une méthode abstraite tryCaptureView et remplace les méthodes suivantes pour implémenter la fonction de glissement latéral. par un.

/** 
* 拦截触摸事件 
* @param ev 
* @return 
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) { 
return dragHelper.shouldInterceptTouchEvent(ev) &&gestureDetector.onTouchEvent(ev); 
} 
/** 
* 将拦截的到事件给ViewDragHelper进行处理 
* @param e 
* @return 
*/
@Override
public boolean onTouchEvent(MotionEvent e){ 
try { 
dragHelper.processTouchEvent(e); 
} catch (Exception ex) { 
ex.printStackTrace(); 
} 
return false; 
}
Copier après la connexion
Il est temps d'intercepter toutes les sous-vues du ViewGroup (dans ce cas : DragLayout) et de renvoyer true directement, indiquant que toutes les sous-vues peuvent être glissées et déplacées.


Implémentez cette méthode pour indiquer un glissement horizontal. En même temps, la méthode déterminera la valeur limite. Par exemple, lorsque la vue principale ci-dessus s'est déplacée vers la gauche et au-delà de la limite. renvoie directement 0, indiquant le plus à gauche. Seul x=0 ; puis se déplacer vers la droite déterminera la distance vers la droite pour atteindre la plage. L'initialisation de la plage sera discutée plus tard. Hormis ces deux situations, il suffit de revenir directement à gauche.

/** 
* 拦截所有的子View 
* @param child Child the user is attempting to capture 
* @param pointerId ID of the pointer attempting the capture 
* @return 
*/
@Override
public boolean tryCaptureView(Viewchild, int pointerId) { 
return true; 
}
Copier après la connexion
Cette méthode est nécessaire à implémenter car cette méthode renvoie 0 par défaut dans le Callback C'est-à-dire que si l'événement click de la vue est vrai, alors la sous-vue entière ne peut pas être déplacée. et situation déplacée. Ensuite, la largeur de la vue gauche est renvoyée directement ici, ce qui représente la distance de glissement horizontal la plus éloignée.

/** 
* 水平方向移动 
* @param child Child view beingdragged 
* @param left Attempted motion alongthe X axis 
* @param dx Proposed change inposition for left 
* @return 
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) { 
if (mainLeft + dx < 0) { 
return 0; 
} else if (mainLeft + dx >range) { 
return range; 
} else { 
return left; 
} 
}
Copier après la connexion
Cette méthode est appelée lorsque le doigt est relâché tout en faisant glisser la sous-vue. Cela déterminera l'intention de se déplacer vers la gauche ou la droite, et ouvrira ou fermera la vue homme (vue supérieure). Voici la dernière méthode implémentée : onViewPositionChanged

/** 
* 设置水平方向滑动的最远距离 
*@param child Child view to check 屏幕宽度 
* @return 
*/
@Override
public int getViewHorizontalDragRange(View child) { 
return width; 
}
Copier après la connexion
Cette méthode est rappelée lors du processus de glisser-déplacer la sous-vue, puis redéfinit la vue gauche et la vue principale en fonction de la position des coordonnées de déplacement . En parallèle, la méthode dispathDragEvent() est appelée pour gérer et distribuer les événements de glisser et rappeler l'interface en fonction du statut :

/** 
* 当拖拽的子View,手势释放的时候回调的方法, 然后根据左滑或者右滑的距离进行判断打开或者关闭 
* @param releasedChild 
* @param xvel 
* @param yvel 
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) { 
super.onViewReleased(releasedChild,xvel, yvel); 
if (xvel > 0) { 
open(); 
} else if (xvel < 0) { 
close(); 
} else if (releasedChild == vg_main&& mainLeft > range * 0.3) { 
open(); 
} else if (releasedChild == vg_left&& mainLeft > range * 0.7) { 
open(); 
} else { 
close(); 
} 
}
Copier après la connexion
Il y a une ligne de code dans cette méthode float percent=mainLeft /(float)range ; compte après un pourcentage Utilisera

/** 
* 子View被拖拽 移动的时候回调的方法 
* @param changedView View whoseposition changed 
* @param left New X coordinate of theleft edge of the view 
* @param top New Y coordinate of thetop edge of the view 
* @param dx Change in X position fromthe last call 
* @param dy Change in Y position fromthe last call 
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, 
int dx, int dy) { 
if (changedView == vg_main) { 
mainLeft = left; 
} else { 
mainLeft = mainLeft + left; 
} 
if (mainLeft < 0) { 
mainLeft = 0; 
} else if (mainLeft > range) { 
mainLeft = range; 
} 
if (isShowShadow) { 
iv_shadow.layout(mainLeft, 0,mainLeft + width, height); 
} 
if (changedView == vg_left) { 
vg_left.layout(0, 0, width,height); 
vg_main.layout(mainLeft, 0,mainLeft + width, height); 
} 
dispatchDragEvent(mainLeft); 
} 
};
Copier après la connexion
5 Quant à l'initialisation de la disposition des sous-vues et à la méthode de réglage de la taille de la largeur, de la hauteur et de la distance de glissement horizontal :

/** 
* 进行处理拖拽事件 
* @param mainLeft 
*/
private void dispatchDragEvent(int mainLeft) { 
if (dragListener == null) { 
return; 
} 
float percent = mainLeft / (float)range; 
//根据滑动的距离的比例 
animateView(percent); 
//进行回调滑动的百分比 
dragListener.onDrag(percent); 
Status lastStatus = status; 
if (lastStatus != getStatus()&& status == Status.Close) { 
dragListener.onClose(); 
} else if (lastStatus != getStatus()&& status == Status.Open) { 
dragListener.onOpen(); 
} 
}
Copier après la connexion
et la méthode de rappel lorsque la taille du contrôle change :


Dans cette méthode, nous pouvons obtenir la largeur, la hauteur et la distance horizontale de traînée en temps réel.

6.上面的所有核心代码都为使用ViewDragHelper实现子控件View拖拽移动的方法,但是根据我们这边侧滑效果还需要实现动画以及滑动过程中View的缩放效果,所以我们这边引入了一个动画开源库:

Android utilise ViewDragHelper pour implémenter la dernière version de lexemple de code deffet dinterface coulissante latérale QQ6.X

然后根据前面算出来的百分比来缩放View视图:

/** 
* 根据滑动的距离的比例,进行平移动画 
* @param percent 
*/
private void animateView(float percent) { 
float f1 = 1 - percent * 0.5f; 
ViewHelper.setTranslationX(vg_left,-vg_left.getWidth() / 2.5f + vg_left.getWidth() / 2.5f * percent); 
if (isShowShadow) { 
//阴影效果视图大小进行缩放 
ViewHelper.setScaleX(iv_shadow, f1* 1.2f * (1 - percent * 0.10f)); 
ViewHelper.setScaleY(iv_shadow, f1* 1.85f * (1 - percent * 0.10f)); 
} 
}
Copier après la connexion

7.当然除了上面这些还缺少一个效果就是,当我们滑动过程中假如我们手指释放,按照常理来讲view就不会在进行移动了,那么这边我们需要一个加速度当我们释放之后,还能保持一定的速度,该怎么样实现呢?答案就是实现computeScroll()方法。

/** 
* 有加速度,当我们停止滑动的时候,该不会立即停止动画效果 
*/
@Override
public void computeScroll() { 
if (dragHelper.continueSettling(true)){ 
ViewCompat.postInvalidateOnAnimation(this); 
} 
}
Copier après la connexion

OK上面关于DragLayout的核心代码就差不多这么多了,下面是使用DragLayout类来实现侧滑效果啦!

(五).侧滑效果组件使用

1.首先使用的布局文件如下:

<com.chinaztt.widget.DragLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dl"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
> 
<!--下层 左边的布局--> 
<includelayoutincludelayout="@layout/left_view_layout"/> 
<!--上层 右边的主布局--> 
<com.chinaztt.widget.CustomRelativeLayout 
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
> 
<LinearLayout 
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
> 
<RelativeLayout 
android:id="@+id/rl_title"
android:layout_width="match_parent"
android:layout_height="49dp"
android:gravity="bottom"
android:background="@android:color/holo_orange_light"
> 
<includelayoutincludelayout="@layout/common_top_bar_layout"/> 
</RelativeLayout> 
<!--中间内容后面放入Fragment--> 
<FrameLayout 
android:layout_width="fill_parent"
android:layout_height="fill_parent"
> 
<fragment 
android:id="@+id/main_info_fragment"
class="com.chinaztt.fragment.OneFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/> 
</FrameLayout> 
</LinearLayout> 
</com.chinaztt.widget.CustomRelativeLayout> 
</com.chinaztt.widget.DragLayout>
Copier après la connexion

该布局文件中父层View就是DragLayout,然后内部有两个RelativeLayout布局,分别充当下一层布局和上一层主布局。

2.下面我们来看一下下层菜单布局,这边我专门写了一个left_view_layout.xml文件,其中主要分为三块,第一块顶部为头像个人基本信息布局,中间为功能入口列表,底部是设置等功能,具体布局代码如下:

<RelativeLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="70dp"
android:background="@drawable/sidebar_bg"
> 
<LinearLayout 
android:id="@+id/ll1"
android:paddingLeft="30dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"> 
<!--头像,昵称信息--> 
<LinearLayout 
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="horizontal"
android:gravity="center_vertical"
> 
<com.chinaztt.widget.RoundAngleImageView 
android:id="@+id/iv_bottom"
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="fitXY"
android:src="@drawable/icon_logo"
app:roundWidth="25dp"
app:roundHeight="25dp"/> 
<LinearLayout 
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:orientation="vertical"> 
<RelativeLayout 
android:layout_width="fill_parent"
android:layout_height="wrap_content"
> 
<TextView 
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="15dp"
android:text="名字:jiangqqlmj"
android:textColor="@android:color/black"
android:textSize="15sp" /> 
<ImageButton 
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="100dp"
android:layout_width="22dp"
android:layout_height="22dp"
android:background="@drawable/qrcode_selector"/> 
</RelativeLayout> 
<TextView 
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="15dp"
android:text="QQ:781931404"
android:textColor="@android:color/black"
android:textSize="13sp" /> 
</LinearLayout> 
</LinearLayout> 
<LinearLayout 
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"> 
<ImageView 
android:layout_width="17dp"
android:layout_height="17dp"
android:scaleType="fitXY"
android:src="@drawable/sidebar_signature_nor"/> 
<TextView 
android:layout_marginLeft="5dp"
android:textSize="13sp"
android:textColor="#676767"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="用心做产品!"/> 
</LinearLayout> 
</LinearLayout> 
<!--底部功能条--> 
<includelayoutincludelayout="@layout/left_view_bottom_layout"
android:id="@+id/bottom_view"
/> 
<!--中间列表--> 
<ListView 
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/bottom_view"
android:layout_below="@id/ll1"
android:layout_marginBottom="30dp"
android:layout_marginTop="70dp"
android:cacheColorHint="#00000000"
android:listSelector="@drawable/lv_click_selector"
android:divider="@null"
android:scrollbars="none"
android:textColor="#ffffff"/> 
</RelativeLayout>
Copier après la connexion

该布局还是比较简单的,对于上层主内容布局这边就放一个顶部导航栏和中的Fragment内容信息,留着后期大家功能扩展即可。

3.主Activity使用如下:

public class MainActivity extends BaseActivity { 
private DragLayout dl; 
private ListView lv; 
private ImageView iv_icon, iv_bottom; 
private QuickAdapter<ItemBean> quickAdapter; 
@Override
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
setStatusBar(); 
initDragLayout(); 
initView(); 
} 
private void initDragLayout() { 
dl = (DragLayout) findViewById(R.id.dl); 
dl.setDragListener(new DragLayout.DragListener() { 
//界面打开的时候 
@Override
public void onOpen() { 
} 
//界面关闭的时候 
@Override
public void onClose() { 
} 
//界面滑动的时候 
@Override
public void onDrag(float percent) { 
ViewHelper.setAlpha(iv_icon, 1 - percent); 
} 
}); 
} 
private void initView() { 
iv_icon = (ImageView) findViewById(R.id.iv_icon); 
iv_bottom = (ImageView) findViewById(R.id.iv_bottom); 
lv = (ListView) findViewById(R.id.lv); 
lv.setAdapter(quickAdapter=new QuickAdapter<ItemBean>(this,R.layout.item_left_layout, ItemDataUtils.getItemBeans()) { 
@Override
protected void convert(BaseAdapterHelper helper, ItemBean item) { 
helper.setImageResource(R.id.item_img,item.getImg()) 
.setText(R.id.item_tv,item.getTitle()); 
} 
}); 
lv.setOnItemClickListener(new OnItemClickListener() { 
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, 
int position, long arg3) { 
Toast.makeText(MainActivity.this,"Click Item "+position,Toast.LENGTH_SHORT).show(); 
} 
}); 
iv_icon.setOnClickListener(new OnClickListener() { 
@Override
public void onClick(View arg0) { 
dl.open(); 
} 
}); 
} 
}
Copier après la connexion

初始化控件,设置滑动监听器,以及左侧菜单功能列表设置即可了,不过上面大家应该看了QuickAdapter的使用,该为BaseAdapterHelper框架使用,我们需要在项目build.gradle中作如下配置:

Android utilise ViewDragHelper pour implémenter la dernière version de lexemple de code deffet dinterface coulissante latérale QQ6.X

具体关于BaseAdapter的使用讲解博客地址如下:

4.正式运行效果如下:

5.因为这边底层需要ViewDragHelper类,所以大家在使用的时候需要导入V4包的,不过我这边直接把ViewGragHelper类的源代码复制到项目中了。

Android utilise ViewDragHelper pour implémenter la dernière version de lexemple de code deffet dinterface coulissante latérale QQ6.X

(六).DragLayout源代码带注释

上面主要分析DragLayout的具体实现,不过我这边也贴一下DragLayout带有注释的全部源代码让大家可以更好的了解DragLayout的具体实现代码:

/** 
*使用ViewRragHelper实现侧滑效果功能 
*/
publicclass DragLayout extends FrameLayout { 
private boolean isShowShadow = true; 
//手势处理类 
private GestureDetectorCompat gestureDetector; 
//视图拖拽移动帮助类 
private ViewDragHelper dragHelper; 
//滑动监听器 
private DragListener dragListener; 
//水平拖拽的距离 
private int range; 
//宽度 
private int width; 
//高度 
private int height; 
//main视图距离在ViewGroup距离左边的距离 
private int mainLeft; 
private Context context; 
private ImageView iv_shadow; 
//左侧布局 
private RelativeLayout vg_left; 
//右侧(主界面布局) 
private CustomRelativeLayout vg_main; 
//页面状态 默认为关闭 
private Status status = Status.Close; 
public DragLayout(Context context) { 
this(context, null); 
} 
public DragLayout(Context context,AttributeSet attrs) { 
this(context, attrs, 0); 
this.context = context; 
} 
public DragLayout(Context context,AttributeSet attrs, int defStyle) { 
super(context, attrs, defStyle); 
gestureDetector = new GestureDetectorCompat(context, new YScrollDetector()); 
dragHelper =ViewDragHelper.create(this, dragHelperCallback); 
} 
class YScrollDetector extends SimpleOnGestureListener { 
@Override
public boolean onScroll(MotionEvent e1,MotionEvent e2, float dx, float dy) { 
return Math.abs(dy) <=Math.abs(dx); 
} 
} 
/** 
* 实现子View的拖拽滑动,实现Callback当中相关的方法 
*/
private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() { 
/** 
* 水平方向移动 
* @param child Child view beingdragged 
* @param left Attempted motion alongthe X axis 
* @param dx Proposed change inposition for left 
* @return 
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) { 
if (mainLeft + dx < 0) { 
return 0; 
} else if (mainLeft + dx >range) { 
return range; 
} else { 
return left; 
} 
} 
/** 
* 拦截所有的子View 
* @param child Child the user isattempting to capture 
* @param pointerId ID of the pointerattempting the capture 
* @return 
*/
@Override
public boolean tryCaptureView(View child, int pointerId) { 
return true; 
} 
/** 
* 设置水平方向滑动的最远距离 
*@param child Child view to check 屏幕宽度 
* @return 
*/
@Override
public int getViewHorizontalDragRange(View child) { 
return width; 
} 
/** 
* 当拖拽的子View,手势释放的时候回调的方法, 然后根据左滑或者右滑的距离进行判断打开或者关闭 
* @param releasedChild 
* @param xvel 
* @param yvel 
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) { 
super.onViewReleased(releasedChild,xvel, yvel); 
if (xvel > 0) { 
open(); 
} else if (xvel < 0) { 
close(); 
} else if (releasedChild == vg_main&& mainLeft > range * 0.3) { 
open(); 
} else if (releasedChild == vg_left&& mainLeft > range * 0.7) { 
open(); 
} else { 
close(); 
} 
} 
/** 
* 子View被拖拽 移动的时候回调的方法 
* @param changedView View whoseposition changed 
* @param left New X coordinate of theleft edge of the view 
* @param top New Y coordinate of thetop edge of the view 
* @param dx Change in X position fromthe last call 
* @param dy Change in Y position fromthe last call 
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, 
int dx, int dy) { 
if (changedView == vg_main) { 
mainLeft = left; 
} else { 
mainLeft = mainLeft + left; 
} 
if (mainLeft < 0) { 
mainLeft = 0; 
} else if (mainLeft > range) { 
mainLeft = range; 
} 
if (isShowShadow) { 
iv_shadow.layout(mainLeft, 0,mainLeft + width, height); 
} 
if (changedView == vg_left) { 
vg_left.layout(0, 0, width,height); 
vg_main.layout(mainLeft, 0,mainLeft + width, height); 
} 
dispatchDragEvent(mainLeft); 
} 
}; 
/** 
* 滑动相关回调接口 
*/
public interface DragListener { 
//界面打开 
public void onOpen(); 
//界面关闭 
public void onClose(); 
//界面滑动过程中 
public void onDrag(float percent); 
} 
public void setDragListener(DragListener dragListener) { 
this.dragListener = dragListener; 
} 
/** 
* 布局加载完成回调 
* 做一些初始化的操作 
*/
@Override
protected void onFinishInflate() { 
super.onFinishInflate(); 
if (isShowShadow) { 
iv_shadow = new ImageView(context); 
iv_shadow.setImageResource(R.mipmap.shadow); 
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 
addView(iv_shadow, 1, lp); 
} 
//左侧界面 
vg_left = (RelativeLayout)getChildAt(0); 
//右侧(主)界面 
vg_main = (CustomRelativeLayout)getChildAt(isShowShadow ? 2 : 1); 
vg_main.setDragLayout(this); 
vg_left.setClickable(true); 
vg_main.setClickable(true); 
} 
public ViewGroup getVg_main() { 
return vg_main; 
} 
public ViewGroup getVg_left() { 
return vg_left; 
} 
@Override
protected void onSizeChanged(int w, int h,int oldw, int oldh) { 
super.onSizeChanged(w, h, oldw, oldh); 
width = vg_left.getMeasuredWidth(); 
height = vg_left.getMeasuredHeight(); 
//可以水平拖拽滑动的距离 一共为屏幕宽度的80% 
range = (int) (width * 0.8f); 
} 
/** 
* 调用进行left和main 视图进行位置布局 
* @param changed 
* @param left 
* @param top 
* @param right 
* @param bottom 
*/
@Override
protected void onLayout(boolean changed,int left, int top, int right, int bottom) { 
vg_left.layout(0, 0, width, height); 
vg_main.layout(mainLeft, 0, mainLeft +width, height); 
} 
/** 
* 拦截触摸事件 
* @param ev 
* @return 
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) { 
returndragHelper.shouldInterceptTouchEvent(ev) &&gestureDetector.onTouchEvent(ev); 
} 
/** 
* 将拦截的到事件给ViewDragHelper进行处理 
* @param e 
* @return 
*/
@Override
public boolean onTouchEvent(MotionEvent e){ 
try { 
dragHelper.processTouchEvent(e); 
} catch (Exception ex) { 
ex.printStackTrace(); 
} 
return false; 
} 
/** 
* 进行处理拖拽事件 
* @param mainLeft 
*/
private void dispatchDragEvent(intmainLeft) { 
if (dragListener == null) { 
return; 
} 
float percent = mainLeft / (float)range; 
//滑动动画效果 
animateView(percent); 
//进行回调滑动的百分比 
dragListener.onDrag(percent); 
Status lastStatus = status; 
if (lastStatus != getStatus()&& status == Status.Close) { 
dragListener.onClose(); 
} else if (lastStatus != getStatus()&& status == Status.Open) { 
dragListener.onOpen(); 
} 
} 
/** 
* 根据滑动的距离的比例,进行平移动画 
* @param percent 
*/
private void animateView(float percent) { 
float f1 = 1 - percent * 0.5f; 
ViewHelper.setTranslationX(vg_left,-vg_left.getWidth() / 2.5f + vg_left.getWidth() / 2.5f * percent); 
if (isShowShadow) { 
//阴影效果视图大小进行缩放 
ViewHelper.setScaleX(iv_shadow, f1* 1.2f * (1 - percent * 0.10f)); 
ViewHelper.setScaleY(iv_shadow, f1* 1.85f * (1 - percent * 0.10f)); 
} 
} 
/** 
* 有加速度,当我们停止滑动的时候,该不会立即停止动画效果 
*/
@Override
public void computeScroll() { 
if (dragHelper.continueSettling(true)){ 
ViewCompat.postInvalidateOnAnimation(this); 
} 
} 
/** 
* 页面状态(滑动,打开,关闭) 
*/
public enum Status { 
Drag, Open, Close 
} 
/** 
* 页面状态设置 
* @return 
*/
public Status getStatus() { 
if (mainLeft == 0) { 
status = Status.Close; 
} else if (mainLeft == range) { 
status = Status.Open; 
} else { 
status = Status.Drag; 
} 
return status; 
} 
public void open() { 
open(true); 
} 
public void open(boolean animate) { 
if (animate) { 
//继续滑动 
if(dragHelper.smoothSlideViewTo(vg_main, range, 0)) { 
ViewCompat.postInvalidateOnAnimation(this); 
} 
} else { 
vg_main.layout(range, 0, range * 2,height); 
dispatchDragEvent(range); 
} 
} 
public void close() { 
close(true); 
} 
public void close(boolean animate) { 
if (animate) { 
//继续滑动 
if(dragHelper.smoothSlideViewTo(vg_main, 0, 0)) { 
ViewCompat.postInvalidateOnAnimation(this); 
} 
} else { 
vg_main.layout(0, 0, width,height); 
dispatchDragEvent(0); 
} 
} 
}
Copier après la connexion

(七).最后总结

今天我们实现打造QQ最新版本QQ6.X效果,同时里边用到了ViewDragHelper,BaseAdapterHelper的运用,具体该知识点的使用方法,我已经在我的博客中更新讲解的文章,欢迎大家查看。

更多Android utilise ViewDragHelper pour implémenter la dernière version de lexemple de code deffet dinterface coulissante latérale QQ6.X相关文章请关注PHP中文网!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal