ListView中有一个控制滑动到边缘的处理方法:
protected boolean overScrollBy(int deltaX,int deltaY,
int scrollX,int scrollY,
int scrollRangeX,int scrollRangeY,
int maxOverScrollX,int maxOverScrollY,
boolean isTouchEvent){
return super.overScrollBy(deltaX, deltaY,
scrollX, scrollY,
scrollRangeX, scrollRangeY,
maxOverScrollX, mMaxOverDistance,
isTouchEvent);
}
可以通过修改maxOverScrollY的值来实现弹性滑动。将父类方法里的maxOverScrollY替换为自定义的mMaxOverDistance就可以实现弹性滑动。另外还可以根据屏幕的分辨率来动态调整该值,使不同分辨率的屏幕显示效果基本一致:
private void init(Context context){
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
float density = metrics.density;
mMaxOverDistance = (int)(density * mMaxOverDistance);
}
通过监听OnTouchListener接口监听ListView的滑动,通过比较上次与上次坐标的大小,来判断滑动的方向,并通过滑动的方向来判断是否需要显示或隐藏对应的布局。在开始判断之前还要先给ListView增加一个HeaderViewm避免第一个Item被Toolbar遮挡。代码如下:
View header = new View(this);
header.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
(int) getResources().getDimension(R.dimen.abc_action_bar_default_height_material)));
mListView.addHeaderView(header);
然后就可以判断滑动事件了:
mListView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int direction = -1;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mFirstY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
mCurrentY = event.getY();
if (mCurrentY - mFirstY > mTouchSlop) {
direction = 0;//down
} else if (mFirstY - mCurrentY > mTouchSlop){
direction = 1;//up
}
if (direction == 1) {
if (mShow) {
toolbarAnim(1);//hide
mShow = !mShow;
}
}else if (direction == 0) {
if (!mShow) {
toolbarAnim(0);//show
mShow = !mShow;
}
}
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
});
其中的mTouchSlop
表示系统能识别的最小的滑动距离,通过如下代码获得:
mTouchSlop=ViewConfiguration.get(this).getScaledTouchSlop();
通过toolbarAnim()
方法来显示或隐藏Toolbar:
private void toolbarAnim(int flag) {
if (mAnimator != null && mAnimator.isRunning()) {
mAnimator.cancel();
}
if (flag == 0) {
mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", mToolbar.getTranslationY(), 0);
Log.i("TAG", "show");
} else {
Log.i("TAG", "hide");
mAnimator = ObjectAnimator.ofFloat(mToolbar, "translationY", mToolbar.getTranslationY(), -mToolbar.getHeight());
}
mAnimator.start();
}
注意要布局要设置成RelativeLayout或者FrameLayout,不能设置成LinearLayout。
BadeAdapter
里有两个方法:getItemViewType(int position)
和getViewTypeCount()
可以用来获得item是何种布局和item布局种类的总数,通过自定义BaseAdapter时重写这两个方法,并在getView()
方法中通过调用这两个方法判断布局类型来实现聊天布局。
@Override
public int getItemViewType(int position){
ChatItemBean bean = getItem(position);
return bean.getType();
}
通过在点击item时在getView()
方法中判断当前点击的item是否是对应点的position,为true的话就通过自定义的getFoucsView()
方法或getNormalView()
来返回不同的布局给convertView。最后不要忘了在点击时间监听里调用notifyDataSetChanged()
方法来刷新,否则getView()
方法不会调用。