1. 程式人生 > >仿照微博詳情頁動態評論滾動頭

仿照微博詳情頁動態評論滾動頭

最近做到一個需求,就是可以懸停的頭部。就是當一個條目在螢幕之下的時候懸停在螢幕最下部,當條目在螢幕上方的時候,懸停在螢幕的頭部。最終效果如下:
這裡寫圖片描述
效果看起來不怎麼好,因為mac上的GiF製作軟體很奇怪,大家先看著吧。真的需要的話可以下載專案來執行試試。
首先我們考慮下實現的思路:
1.由於內容可滑動我們最好是放在listview 中。
2.由於listview的頭部很大,可能超出螢幕,所以這個時候我們控制元件應該顯示螢幕的最下方。
3.listview是有內容的,當內容很長的時候我們的頭部是會被移動到螢幕的上面然後移除螢幕,此時我們需要將這個評論控制元件顯示在螢幕的最上方。
好了這個就是具體的需求那我們怎麼做呢:
1.我們可以重寫listview的滑動事件,監聽當評論的的頭部滑到螢幕listview的頭部時我們顯示我們提前寫好的一樣的控制元件,這樣使用者看起來就是一個控制元件在使用。那麼底部也是同理了。具體我們看程式碼:
activity程式碼:

package com.example.songzhihang.listheadtest;

import android.graphics.Rect;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import
android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements AbsListView.OnScrollListener { private static final String TAG = "MainActivity"
; int padding; TextView textview; private int statusBarHeight; private int contentTop; private int titleBarHeight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(new MyAdapter()); listView.setOnScrollListener(this); textview = (TextView) findViewById(R.id.text); padding=((View)(textview.getParent())).getPaddingTop()+ ((View)(textview.getParent())).getPaddingBottom(); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); Rect frame = new Rect(); getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); statusBarHeight = frame.top; //狀態列高 contentTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop(); titleBarHeight = contentTop - statusBarHeight; //標題欄高 Log.e(TAG, "statusBarHeight: "+statusBarHeight ); Log.e(TAG, "contentTop: "+contentTop ); Log.e(TAG, "titleBarHeight: "+titleBarHeight ); } class MyAdapter extends BaseAdapter { @Override public int getCount() { return 20; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); convertView = new TextView(MainActivity.this); holder.view = (TextView) convertView; convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.view.setText("我是:" + position); holder.view.setTextSize(30); return convertView; } class ViewHolder { TextView view; } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } /** **重寫滑動的方法 **/ @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { View firstItem = view.getChildAt(0); textview = (TextView) MainActivity.this.findViewById(R.id.text); if (firstItem != null && firstItem instanceof LinearLayout) { Log.e(TAG, "firstItem.getY(): " + firstItem.getY()); Log.e(TAG, "firstItem.getHeight(): " + firstItem.getHeight()); Log.e(TAG, "view.getY(): " + view.getY()); Log.e(TAG, "onScroll: " + ((LinearLayout) firstItem).getChildAt(1).getHeight()); Log.e(TAG, "padding: " + padding); //當前控制元件的Y座標(由於螢幕左上角是原點,那麼螢幕都是負數)的負數大於等於到控制元件的高度的時候說明此事控制元件在螢幕中,那就影藏我們的備用控制元件,否則控制元件移除螢幕顯示我們的備用控制元件 // 由於我們的頭部是個Linlayout,有2個子控制元件,所以我們的控制元件高度等於總高度減去第一個位置的控制元件高度 if (-firstItem.getY() >= firstItem.getHeight() - ((LinearLayout) firstItem).getChildAt(1).getHeight()) { textview.setVisibility(View.VISIBLE); } else { textview.setVisibility(View.GONE); } //通過螢幕的高度找到底部的位置,加上控制元件的高度,表明此事控制元件在最底部 // if(getWinHeight()-view.getY()-padding-contentTop<=firstItem.getY()+firstItem.getHeight()){ if(-firstItem.getY()<=680){ findViewById(R.id.buttom_text).setVisibility(View.VISIBLE); }else{ findViewById(R.id.buttom_text).setVisibility(View.GONE); } } else { textview.setVisibility(View.VISIBLE); findViewById(R.id.buttom_text).setVisibility(View.GONE); } } private int getWinHeight() { WindowManager wm = this.getWindowManager(); int height = wm.getDefaultDisplay().getHeight(); Log.e(TAG, "getWinHeight: "+height ); return height; } }

接下來看下佈局檔案:其中提前定義好的兩個備用那個控制元件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.songzhihang.listheadtest.MainActivity">

    <View
        android:id="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#ff0"></View>


        <com.example.songzhihang.listheadtest.CusListView
            android:layout_below="@+id/view"
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:scrollbars="none"
            android:layout_height="match_parent"></com.example.songzhihang.listheadtest.CusListView>

    <TextView
        android:id="@+id/text"
        android:layout_below="@+id/view"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="我是頭部"
        android:visibility="gone"
        android:background="#fff"
        />

    <TextView
        android:id="@+id/buttom_text"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="我是頭部"
        android:visibility="gone"
        android:background="#fff"
        />

</RelativeLayout>

然後看下自定的listview其中包含2個頭部:

package com.example.songzhihang.listheadtest;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;

/**
 * @discription
 * @autor songzhihang
 * @time 2017/3/15  下午8:58
 **/
public class CusListView extends ListView{


    public CusListView(Context context) {
        super(context);
        init();
    }

    public CusListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CusListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

     void init(){

         LinearLayout headView=new LinearLayout(getContext());
         LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//         headView.setLayoutParams(params);
         headView.setOrientation(LinearLayout.VERTICAL);

         //內容佈局
         View misshead=inflate(getContext(),R.layout.dismiss_head_layout,null);
         //長期駐存在螢幕的控制元件頭
         View showhead=inflate(getContext(),R.layout.head_layout,null);

         headView.addView(misshead);
         headView.addView(showhead);
         addHeaderView(headView);

    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(ev);
    }
}

其實這只是個思路,具體的話實現了我們可以做很多的事情,達到很多的效果。想看原始碼的同學可以看我的Github,地址:這裡寫連結內容