Android Scroller詳解,實現仿QQ列表item側滑刪除功能
阿新 • • 發佈:2019-02-14
概述
Scroller,主要用於實現View的滾動。這個滾動主要是指平滑滾動
要想通過Scroller實現滑動,只要實現以下步驟即可:
- 建立一個Scroller物件,呼叫startScroll方法,然後呼叫invalidate()方法重新繪製View
- 重寫View的computeScroll方法
- 在computeScroll方法中,呼叫Scroller的computeScrollOffset方法,該方法用於判斷滑動是否結束
- 如果滑動沒有結束,通過呼叫scrollTo方法和postInvalidate方法完成滑動
簡單程式碼實現如下:
//1、啟動滑動
public void scroll (){
Scroller.startScroll(getScrollX(), getScrollY(), offsetX, offsetY);
invalidate();
}
//實現具體的滑動邏輯
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
scrollTo和scrollBy介紹
在Android的View類中,已經為大家提供了scrollTo和scrollBy方法實現View的滑動。
scrollTo和scrollBy方法的區別:
- scrollTo:絕對位置滑動,即相對View的初始位置滑動。
- scrollBy:相對位置滑動,即相對View的當前位置滑動。
通過檢視原始碼可知,scrollBy方法的內部也是通過呼叫scrollTo方法實現的:
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
public void scrollBy(int x, int y) {
//其中mScrollX、和mScrollY表示相對初始位置的滑動距離
// x、y表示滑動偏移量
scrollTo(mScrollX + x, mScrollY + y);
}
這裡有一點需要注意scrollTo和scrollBy方法中的引數:向右滑動引數為負值,向左滑動引數為正值
實現QQ側滑控制元件
程式碼如下:
package com.zhangke.a07_02_scrollerdemo1;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
import android.widget.Scroller;
/**
* 仿QQ item側滑刪除按鈕
*/
public class SlidingLinearLayout extends LinearLayout {
private View leftView;
private View rightView;
private Scroller mScroller;
private int mTouchSlop;
private float startX;
private float startY;
private float distX;
private float distY;
public SlidingLinearLayout(Context context) {
this(context, null);
}
public SlidingLinearLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//建立一個Scroller物件
mScroller = new Scroller(getContext());
//表示系統指定的滑動的最小距離
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//正常顯示的view
leftView = getChildAt(0);
//通過滑動顯示的view
rightView = getChildAt(1);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
super.dispatchTouchEvent(event);
return true;
case MotionEvent.ACTION_MOVE:
distX = event.getX() - startX;
distY = event.getY() - startY;
//判斷是否是左右滑動
if (Math.abs(distX) - Math.abs(distY) > mTouchSlop) {
//判斷滑動的邊界:0 ~ rightView.getWidth()
//因為View是向左滑動的,那麼View的偏移量是大於0的,那麼通過getScrollX的值大於0,通過(-distX)也是大於0的
float offsetX = getScrollX() + (-distX);
if (offsetX > rightView.getWidth() || offsetX < 0) {
return true;
}
//向左滑動,引數為正
scrollBy((int) -distX, 0);
startX = event.getX();
startY = event.getY();
return true;
}
break;
case MotionEvent.ACTION_UP:
//當鬆開手指時、判斷滑動是否大於rightView的一半,如果大於那麼完全顯示rightView,否則隱藏rightView
//計算偏移量
int offset = getScrollX() / (float) rightView.getWidth() > 0.5f ? rightView.getWidth() - getScrollX() : -getScrollX();
//實現滑動
mScroller.startScroll(getScrollX(), getScrollY(), offset, 0);
invalidate();
startX = 0;
startY = 0;
distX = 0;
distY = 0;
break;
}
return super.onTouchEvent(event);
}
@Override
public void computeScroll() {
super.computeScroll();
//判斷滑動是否結束
if (mScroller.computeScrollOffset()) {
//通過scrollTo方法滑動
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
}
在專案中使用
activity程式碼:
package com.zhangke.a07_02_scrollerdemo1;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<String> datas;
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listview);
datas = new ArrayList<String>();
for (int i = 0; i < 20; i++) {
datas.add("item " + i);
}
listView.setAdapter(new MyAdapter());
}
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(MainActivity.this, R.layout.item, null);
}
TextView textview = (TextView) convertView.findViewById(R.id.textview);
textview.setText(datas.get(position));
return convertView;
}
}
}
item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.zhangke.a07_02_scrollerdemo1.SlidingLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/colorAccent"
android:orientation="horizontal">
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="正常顯示的view" />
<LinearLayout
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@color/colorPrimaryDark"
android:orientation="horizontal">
<TextView
android:layout_width="50dp"
android:layout_height="50dp"
android:gravity="center"
android:background="#8bc662"
android:text="置頂" />
<TextView
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#5694ff"
android:gravity="center"
android:text="刪除" />
</LinearLayout>
</com.zhangke.a07_02_scrollerdemo1.SlidingLinearLayout>
效果圖: