寫一寫虎撲APP首頁效果,jrs都進來看一眼!
阿新 • • 發佈:2019-02-04
首先先上效果圖:
首先我們先考慮這個介面有什麼難點:
1.日期懸停。
2.今日和其他日期在懸停佈局上的處理
3.首次進入時,自動滑動到今日比賽
4.向上滑動向下滑動一定距離後,出現向上向下的圖示,並滾動到今日的比賽介面
5.向上載入更多,向下載入更多,當然這個並不算是難點,只是比較新穎~。
好了,首先我們一項一項的開始解決這幾個難點,首先這樣的列表佈局,強烈推薦大家使用RecyclerView,谷歌粑粑真的是賦予了它無窮的潛力。觀看本文前依然推薦一波部落格地址:點選開啟連結 一個頭像狂魔的部落格。
如果你已經看過了上篇部落格,你可能會對這個介面已經有一定的瞭解,那麼首先我們實現ItemDecoration的編寫,首先我們應該考慮後臺與我們互動時給出來的資料,一般為List或者Map格式,所以我們在編寫時應充分考慮兩種格式寫法上的差異(其實也沒什麼差異的地方)。
這裡的HuPuBaseBean是一個bean類,內部實現了getDayType的方法,這裡是基於封裝而寫出的基類,如果在實際專案中可以直接引入我們所需要的實體類來進行賦值。public class HuPuItemDecoration<T extends HuPuBaseBean> extends RecyclerView.ItemDecoration { private int todayPosition; private List<T> mData; private Map<String, List<T>> mapData; private Paint mPaint; private int itemHeight; private int background; private int textSize; private int textColor; private Context context; private Rect outBounds = new Rect(); public HuPuItemDecoration(Context context, int todayPosition, List<T> mData) { this.context = context; this.todayPosition = todayPosition; this.mData = mData; mPaint = new Paint(); itemHeight = dip2px(context, 25); background = ContextCompat.getColor(context, android.R.color.darker_gray); textSize = sp2px(context, 15); textColor = ContextCompat.getColor(context, android.R.color.black); } public HuPuItemDecoration(Context context, int todayPosition, Map<String, List<T>> mapData) { this.context = context; this.todayPosition = todayPosition; this.mapData = mapData; mPaint = new Paint(); itemHeight = dip2px(context, 25); background = ContextCompat.getColor(context, android.R.color.darker_gray); textSize = sp2px(context, 15); textColor = ContextCompat.getColor(context, android.R.color.black); for (Map.Entry<String, List<T>> entry : mapData.entrySet()) { mData.addAll(entry.getValue()); } }
初始化完成後,我們開始一步一步實現:程式碼很簡單,一梭子給出來一部分先:
關於這部分方法的意義,推薦大家去鴻洋sama的部落格去充值信仰!!!:點選開啟連結
這裡的程式碼邏輯比較簡單,就是當position==0時,我們必然會有一個divider去標識日期,而後當前的type不等於它所在位置的上一個position的type時,這時兩個position所在的view中間應有一個divider來進行標識!這部分程式碼非常的簡單,我們繼續一梭子擼下面的程式碼:@Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); if (null != mData && null != mapData) { throw new IllegalArgumentException("這裡不會走到的,只是判斷一下"); } if (position > -1) { if (position == 0) { outRect.set(0, itemHeight, 0, 0); } else { if (!mData.get(position).getDayType().equals(mData.get(position - 1).getDayType())) { outRect.set(0, itemHeight, 0, 0); } else { outRect.set(0, 0, 0, 0); } } } }
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
int left = parent.getPaddingLeft();
int right = parent.getRight() - parent.getPaddingRight();
int count = parent.getChildCount();
for (int i = 0; i < count; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
int position = lp.getViewLayoutPosition();
if (position == 0) {
mPaint.setColor(background);
c.drawRect(left, child.getTop() - itemHeight - lp.topMargin, right, child.getTop() - lp.topMargin, mPaint);
mPaint.setColor(textColor);
mPaint.setTextSize(textSize);
String type = mData.get(position).getDayType();
mPaint.getTextBounds(type, 0, type.length(), outBounds);
c.drawText(type, child.getRight() / 2 - outBounds.width() / 2, child.getTop() - lp.topMargin -
(itemHeight / 2 - outBounds.height() / 2), mPaint);
} else {
if (!mData.get(position).getDayType().equals(mData.get(position - 1).getDayType())) {
mPaint.setColor(background);
c.drawRect(left, child.getTop() - itemHeight - lp.topMargin, right, child.getTop() - lp.topMargin, mPaint);
if (position == todayPosition) {
mPaint.setColor(Color.RED);
c.drawRect(left, child.getTop() - itemHeight - lp.topMargin, 15, child.getTop() - lp.topMargin, mPaint);
}
mPaint.setColor(background);
mPaint.setTextSize(textSize);
mPaint.setColor(textColor);
String type = mData.get(position).getDayType();
mPaint.getTextBounds(type, 0, type.length(), outBounds);
c.drawText(type, child.getRight() / 2 - outBounds.width() / 2, child.getTop() -
lp.topMargin - (itemHeight / 2 - outBounds.height() / 2), mPaint);
} else {
}
}
}
}
這部分程式碼其實跟上面的程式碼在邏輯上非常接近,如果你已經看了最上面的部落格連結,這裡的邏輯你應該也能看得懂,這裡和推薦部落格在這裡並沒有什麼不同,如果這裡有任何疑問,我強烈大家去推薦部落格那裡去看詳細的解釋,(什麼是甩鍋,這就叫甩鍋)。
最後一段程式碼:
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
int position = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition();
View itemView = parent.findViewHolderForAdapterPosition(position).itemView;
if (mData.size() - 1 >= position) {
if (!mData.get(position).getDayType().equals(mData.get(position + 1).getDayType())) {
if (itemView.getHeight() + itemView.getTop() < itemHeight) {
c.translate(0, itemView.getHeight() + itemView.getTop() - itemHeight);
}
}
}
mPaint.setColor(background);
c.drawRect(parent.getPaddingLeft(), parent.getPaddingTop(), parent.getRight() - parent.getPaddingRight(),
parent.getPaddingTop() + itemHeight, mPaint);
if (position >= todayPosition && mData.get(todayPosition).getDayType().equals(mData.get(position).getDayType())) {
mPaint.setColor(Color.RED);
c.drawRect(parent.getPaddingLeft(), parent.getPaddingTop(), 15, parent.getPaddingTop() + itemHeight, mPaint);
}
mPaint.setColor(textColor);
mPaint.setTextSize(textSize);
String dayType = mData.get(position).getDayType();
mPaint.getTextBounds(dayType, 0, dayType.length(), outBounds);
c.drawText(dayType, (parent.getRight() - parent.getPaddingRight() - parent.getPaddingLeft() - outBounds.width()) / 2,
parent.getPaddingTop() + itemHeight - (itemHeight / 2 - outBounds.height() / 2), mPaint);
}
這裡就是做懸停部分的程式碼,這裡唯一需要注意的就是我們對於今日比賽懸停介面的處理。
if (position >= todayPosition && mData.get(todayPosition).getDayType().equals(mData.get(position).getDayType())) {
mPaint.setColor(Color.RED);
c.drawRect(parent.getPaddingLeft(), parent.getPaddingTop(), 15, parent.getPaddingTop() + itemHeight, mPaint);
}
如果當前的position大於等於我們傳過來的todayPos,然後type相等,既判定為今日比賽。其他則無視之。
寫完了這部分程式碼後,我們就簡單寫一個RecyclerView出來:
rv = (RecyclerView) findViewById(R.id.rv);
top= (ImageView) findViewById(R.id.top);
bottom= (ImageView) findViewById(R.id.bottom);
for (int i = 0; i < 10; i++) {
HuPuBean bean = new HuPuBean("雷霆", "火箭", "早上8:00", 124, 100, "昨日", false);
mData.add(bean);
}
for (int i = 0; i < 10; i++) {
HuPuBean bean = new HuPuBean("雷霆", "火箭", "早上8:00", 124, 100, "今日", true);
mData.add(bean);
}
for (int i = 0; i < 10; i++) {
HuPuBean bean = new HuPuBean("雷霆", "火箭", "早上8:00", 124, 100, "明日", true);
mData.add(bean);
}
rv.addItemDecoration(new HuPuItemDecoration<HuPuBean>(MainActivity.this, Utils.getTodayPosition("今日", mData), mData));
final LinearLayoutManager manger = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false);
rv.setLayoutManager(manger);
rv.setAdapter(new RecyclerView.Adapter<Holder>() {
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, parent, false);
return new Holder(itemView);
}
@Override
public void onBindViewHolder(Holder holder, int position) {
HuPuBean bean = mData.get(position);
holder.teamOne.setText(bean.getTeamOne());
holder.teamTwo.setText(bean.getTeamTwo());
holder.teamOnePoint.setText("" + bean.getTeamOnePoint());
holder.teamOnePoint.setText("" + bean.getTeamTwoPoint());
}
@Override
public int getItemCount() {
return mData.size();
}
});
這裡程式碼寫得比較粗糙,勿怪。
然後我們來看一下效果圖。
我們來看一下utils方法,也非常簡單,因為涉及到載入重新整理的邏輯,todayPostion的位置會發生改變,不建議使用賦值,
public class Utils {
public static int getTodayPosition(String type, List<? extends HuPuBaseBean> mData) {
for (int i = 0; i < mData.size(); i++) {
if (mData.get(i).getDayType().equals(type)) {
return i;
}
}
return 0;
}
}
最後我們來處理上滑下滑時top bottom圖片的顯示隱藏:
首先我們看MianActivity的佈局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rv"
></android.support.v7.widget.RecyclerView>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="right"
android:layout_marginTop="20dp"
android:layout_marginRight="20dp"
android:id="@+id/bottom"
android:background="@mipmap/ic_launcher"
android:visibility="gone"
/>
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="bottom|right"
android:layout_marginBottom="20dp"
android:layout_marginRight="20dp"
android:id="@+id/top"
android:background="@mipmap/ic_launcher"
android:visibility="gone"
/>
</FrameLayout>
然後通過RecyclerView的對滑動監聽來實現兩張圖片的顯示和隱藏:
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int position = manger.findFirstVisibleItemPosition();
if(position-Utils.getTodayPosition("今日",mData)>=10){
bottom.setVisibility(View.GONE);
top.setVisibility(View.VISIBLE);
}else if(position-Utils.getTodayPosition("今日",mData)<=-10){
bottom.setVisibility(View.VISIBLE);
top.setVisibility(View.GONE);
}else {
bottom.setVisibility(View.GONE);
top.setVisibility(View.GONE);
}
}
});
當然這種實現方式是最常見的,不過我們還可以通過自定義behavior這種方式來實現滑動的聯動效果,但是本篇就不在這裡實現了。
最後首次載入滑動到今日比賽,和點選圖片滑動到今日比賽,其實非常簡單,一行程式碼搞定:
manger.scrollToPositionWithOffset(Utils.getTodayPosition("今日", mData), 0);
至此,基本的虎撲看球頁面的效果就已經實現了,是不是非常簡單,當然虎撲的頁面更加複雜,itemType有數種,這裡就不再實現了。最後去愉快的水群了。臨走前在發一張我老婆的美圖: