安卓作業----慕課移動互聯網作業9利用ViewDragHelper實現qq消息欄側滑刪除效果

此博客利用ViewDragHelper實現qq消息欄側滑刪除效果,同時這也是中國大學慕課移動終端應用開發的網課作業9,我會持續更新我的作業,如果有需要關注一下吧

說明

1.由於涉及到沒有學過的內容,自學的時候參考了此篇博文菜鳥教程,並在原基礎上做了優化,並補充了幾乎每個新知識的註釋。

2.粘貼的時候注意包的正確導入,Message實體類不要和安卓的消息類混淆

3.注意修改佈局文件item.xml上ViewGroup的包名,android studio不會主動報錯,但是要修改,不然無法通過編譯

4.還有其他注意點我想到了再補充……嘿嘿

哦對了,作業8太簡單我就不寫了

效果圖

在這裏插入圖片描述

代碼部分

代碼分成四個部分,第一部分是消息實體類Message.java,第二部分是ListView的子佈局,涉及到item.xml佈局文件和TranslationLayout.java自定義佈局,第三部分是適配器MessageAdapter.java,第四部分是主界面MainActivity.java和activity_main.xml主佈局文件。以下是具體內容:

Message.java
/**
 * 消息實體類
 * */
public class Message {
    private String name;    //姓名
    private String content; //內容
    private String date;    //日期
    private int img;        //頭像id資源

    public Message() {
    }

    public Message(String name, String content) {
        this.name = name;
        this.content = content;
        this.date = "6:00 am";
        this.img = R.drawable.boy;
    }

    public Message(String name, String content, String date, int img) {
        this.name = name;
        this.content = content;
        this.date = date;
        this.img = img;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public int getImg() {
        return img;
    }

    public void setImg(int img) {
        this.img = img;
    }
}
item.xml
<?xml version="1.0" encoding="utf-8"?>
<com.example.course9.mylayout.TranslationLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:paddingLeft="5dp"
        android:background="#DCF5F1">

        <ImageView
            android:id="@+id/image"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/boy"
            />

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@+id/image"
            android:layout_alignBottom="@+id/image"
            android:layout_toRightOf="@+id/image"
            android:layout_marginLeft="15dp"
            tools:ignore="RtlHardcoded">

            <TextView
                android:id="@+id/name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="大青兒"
                android:textSize="25dp"
                android:textColor="#F1A46C"
                />

            <TextView
                android:id="@+id/content"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingTop="2dp"
                android:text="早上好鐵子"
                android:textSize="15dp"
                android:textColor="#222121"
                android:layout_alignParentBottom="true"
                />

            <TextView
                android:id="@+id/time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="6:00 am"
                android:textSize="19sp"
                android:textColor="#FF7F7F80"
                android:layout_alignParentRight="true"
                android:padding="10dp"
                android:paddingRight="20dp"
                />
        </RelativeLayout>

    </RelativeLayout>

    <LinearLayout
        android:layout_width="200dp"
        android:layout_height="60dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/to_top"
            android:layout_width="66.5dp"
            android:layout_height="match_parent"
            android:text="置頂"
            android:textColor="#FFF"
            android:textSize="17sp"
            android:gravity="center"
            android:background="#FFC6C6CC"/>
        <TextView
            android:id="@+id/have_read"
            android:layout_width="66.5dp"
            android:layout_height="match_parent"
            android:textColor="#FFF"
            android:textSize="17sp"
            android:text="已讀"
            android:gravity="center"
            android:background="#FFFD9C01"/>
        <TextView
            android:id="@+id/delete"
            android:layout_width="66.5dp"
            android:layout_height="match_parent"
            android:textColor="#FFF"
            android:textSize="17sp"
            android:text="刪除"
            android:gravity="center"
            android:background="#FFFD3A30" />
    </LinearLayout>


</com.example.course9.mylayout.TranslationLayout>
TranslationLayout.java

此爲自定義佈局,這一部分是本博客的重中之重,幾乎每一處的代碼我都寫有註釋,李姐萬歲

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.customview.widget.ViewDragHelper;

public class TranslationLayout extends LinearLayout {
    private ViewDragHelper mViewDragHelper;//定義mViewDragHelper

    public boolean directionFlag = true;//移動方向的標誌,true爲左,false爲右

    private int screenWidth;//屏幕的寬度
    private Context mContext;//上下文對象

    private View firstView;//第一個view對象
    private View secondView;//第二個view對象

    private int secondViewWidth;//第二個view的長度

    private final String TAG = "TranslationLayoutTAG";//logcat的標記

    public TranslationLayout(Context context) {
        super(context);
        this.mContext = context;
        init();
    }

    public TranslationLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        init();
    }

    public TranslationLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        init();
    }

    //初始化方法
    private void init(){
        mViewDragHelper = ViewDragHelper.create(this,new MyCallBack());
        //獲取屏幕的長度
        WindowManager wm=(WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        screenWidth = outMetrics.widthPixels;
    }

    //在第一次渲染結束的時候,獲取兩個子View
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        firstView = getChildAt(0);//獲取第一個子view,一開始顯示的那個
        secondView = getChildAt(1);//獲取第二個view,後面隱藏的,側滑之後才能看見
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //獲取第二個view的長度
        secondViewWidth = secondView.getMeasuredWidth();
    }

    //在onInterceptTouchEvent中授權mViewDragHelper.shouldInterceptTouchEvent(ev)
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    //在onTouchEvent中授權 mViewDragHelper.processTouchEvent(event);
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 處理相應的TouchEvent的時候要將結果返回爲true,消費本次事件
        //否則將無法使用ViewDragHelper處理相應的拖拽事件
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

    //重寫的ViewGroup的方法,主要是用於ViewGroup中更新相應View
    @Override
    public void computeScroll() {
        super.computeScroll();
        if(mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    //內部類
    private class MyCallBack extends ViewDragHelper.Callback{
        private int left;

        //必須實現此方法,也只有在這個方法返回true的時候下面的方法纔會生效
        @Override
        public boolean tryCaptureView(@NonNull View child, int pointerId) {
            return true;
        }

        /**
         * 當狀態改變的時候回調,返回相應的狀態(這裏有三種狀態)
         *         STATE_IDLE 閒置狀態
         *         STATE_DRAGGING 正在拖動
         *         STATE_SETTLING 放置到某個位置
         * */
        @Override
        public void onViewDragStateChanged(int state) {
            super.onViewDragStateChanged(state);
        }

        /**
         * 位置發生改變的時候回調
         *             參數1:你當前拖動的這個View
         *             參數2:距離左邊的距離
         *             參數3:距離上邊的距離
         *             參數4:x軸的變化量
         *             參數5:y軸的變化量
         * */
        @Override
        public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            //如果第一個view被拖動,第二個view(被隱藏那個)也跟着移動
            if (changedView == firstView){
                secondView.offsetLeftAndRight(dx);
            }else {//如果移動的是第二個,第一個view也跟着移動
                firstView.offsetLeftAndRight(dx);
            }
            this.left = left;
            //更新ui
            invalidate();
        }

        /**
         * 在該方法中對child移動的水平邊界進行控制,left表示即將移動到的位置。
         * */
        @Override
        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
            return Math.min(Math.max(-secondViewWidth, left), 0);//使其不能向右滑動;
        }

        /**
         * 垂直邊界進行控制
         * */
        @Override
        public int getViewVerticalDragRange(View child) {
            return 0;
        }

        //停止拖拽的時候
        @Override
        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);

            Log.d(TAG,"firstView.getRight():"+firstView.getRight());
            //getRight()方法返回的是組件右邊到屏幕左邊的距離
            //觸發左移的條件是移動超過50dp並且方向向左
            if(firstView.getRight()<(screenWidth-50)&&directionFlag){
                //將第一個View向左移動第二個view寬度
                mViewDragHelper.smoothSlideViewTo(firstView,-secondViewWidth, 0);
                //更新ui
                ViewCompat.postInvalidateOnAnimation(TranslationLayout.this);
                //方向設置爲右邊
                directionFlag = false;
            } else {//方向爲右邊或者移動小於50dp
                //將第一個View移動回去
                mViewDragHelper.smoothSlideViewTo(firstView, 0, 0);
                //更新ui
                ViewCompat.postInvalidateOnAnimation(TranslationLayout.this);
                //方向設置爲左邊
                directionFlag = true;
            }
        }
    }
}
MessageAdapter.java
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.course9.R;
import com.example.course9.model.Message;

import java.util.ArrayList;

public class MessageAdapter extends BaseAdapter {
    private Context mContext;//上下文對象
    private ArrayList<Message> mMessages;//對象數組

    //有參構造方法
    public MessageAdapter(Context context, ArrayList<Message> messages) {
        mContext = context;
        mMessages = messages;
    }

    //無參構造方法
    public MessageAdapter() { }

    //返回數據大小
    @Override
    public int getCount() {
        return mMessages.size();
    }

    @Override
    public Object getItem(int position) {
        return mMessages.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null){
            holder = new ViewHolder();
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item,parent,false);
            holder.mImageViewImg = convertView.findViewById(R.id.image);
            holder.mTextViewName = convertView.findViewById(R.id.name);
            holder.mTextViewContent = convertView.findViewById(R.id.content);
            holder.mTextViewDate = convertView.findViewById(R.id.time);
            convertView.setTag(holder); //將Holder存儲到convertView中
        }else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.mImageViewImg.setBackgroundResource(mMessages.get(position).getImg());
        holder.mTextViewName.setText(mMessages.get(position).getName());
        holder.mTextViewContent.setText(mMessages.get(position).getContent());
        holder.mTextViewDate.setText(mMessages.get(position).getDate());

        return convertView;
    }

    //內部類
    private class ViewHolder{
        public ImageView mImageViewImg;
        public TextView mTextViewName,mTextViewContent,mTextViewDate;
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:id="@+id/my_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none">
    </ListView>
</LinearLayout>
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.ListView;

import com.example.course9.adapter.MessageAdapter;
import com.example.course9.model.Message;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private ListView mListView;//定義ListView
    private ArrayList<Message> mMessages;

    private void init(){
        mListView = findViewById(R.id.my_list_view);
        mMessages = new ArrayList<>();
        //放入數據
        Message message1 = new Message("大青兒","今天早上我這好像下雪了,你那邊呢");
        Message message2 = new Message("小錢","和平精英,速速上線,快快快!!!");
        Message message3 = new Message("小謝","科目三好難啊,感覺比考研還難咋辦啊鐵子");
        Message message4 = new Message("小王","明天出來搓一頓啊");
        Message message5 = new Message("特朗普","我比任何人都要懂安卓,我知道");
        Message message6 = new Message("老媽","今天天氣好冷,你要多穿一點衣服");
        mMessages.add(message1);
        mMessages.add(message2);
        mMessages.add(message3);
        mMessages.add(message4);
        mMessages.add(message5);
        mMessages.add(message6);

        MessageAdapter adapter = new MessageAdapter(this,mMessages);
        mListView.setAdapter(adapter);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
}

圖片資源

圖片資源來自阿里巴巴矢量圖標庫

boy.png,放入drawable文件夾中
在這裏插入圖片描述

最後

碼字不易,如有幫助,點贊關注分享給個好評哦親

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章