日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android 日程安排view,RecyclerView 列表控件中简单实现时间线

發(fā)布時(shí)間:2025/3/12 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 日程安排view,RecyclerView 列表控件中简单实现时间线 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

時(shí)間

時(shí)間,時(shí)間,時(shí)間啊;走慢一點(diǎn)吧~

看見很多軟件中都有時(shí)間線的東西,貌似天氣啊,旅游啊什么的最多了;具體實(shí)現(xiàn)方式很多,在本篇文章中講解一種自定義View封裝的方式。

效果

先來看看效果。

分析

軟件中,可以看見前面的時(shí)間線也就是線條加上圓圈組成;當(dāng)然這里的圓圈與線條也都是可以隨意換成其他的,比如圖片等等。

當(dāng)然這里最簡單的來說,是上面一個(gè)線條,然后一個(gè)圓圈,然后下面一個(gè)線條;上線條在第一條數(shù)據(jù)時(shí)不做顯示,下線條在最后一條數(shù)據(jù)時(shí)不做顯示。

這里自定義布局部分也就是把旁邊的線條與圓圈封裝到一起,并使用簡單的方法來控制是否顯示。?當(dāng)封裝好了后,與旁邊的文字部分也就是水瓶方向的線性布局了,然后設(shè)置為每一個(gè)的RecyclerView 的Item的布局也就完成了。

控件

控件很簡單,首先我們繼承View,取名為 TimeLineMarker 就OK。

Attrs 屬性

開始控件之前先準(zhǔn)備好需要的屬性。<?xml ?version="1.0"?encoding="utf-8"?>

在這里也就準(zhǔn)備了線條的大小、開始線條、結(jié)束線條、中間標(biāo)示部分及大小。

屬性與現(xiàn)實(shí)private?int?mMarkerSize?=?24;

private?int?mLineSize?=?12;

private?Drawable?mBeginLine;

private?Drawable?mEndLine;

private?Drawable?mMarkerDrawable;

@Override

protected?void?onDraw(Canvas?canvas)?{

if?(mBeginLine?!=?null)?{

mBeginLine.draw(canvas);

}

if?(mEndLine?!=?null)?{

mEndLine.draw(canvas);

}

if?(mMarkerDrawable?!=?null)?{

mMarkerDrawable.draw(canvas);

}

super.onDraw(canvas);

}

兩個(gè)大小屬性,3個(gè)具體的Drawable,然后在onDraw方法中進(jìn)行具體的顯示也就OK。

構(gòu)造與屬性初始化

在上面我們定義了屬性,在這里我們在構(gòu)造函數(shù)中獲取XML所設(shè)置的屬性。public?TimeLineMarker(Context?context)?{

this(context,?null);

}

public?TimeLineMarker(Context?context,?AttributeSet?attrs)?{

this(context,?attrs,?0);

}

public?TimeLineMarker(Context?context,?AttributeSet?attrs,?int?defStyle)?{

super(context,?attrs,?defStyle);

init(attrs);

}

private?void?init(AttributeSet?attrs)?{

//?Load?attributes

final?TypedArray?a?=?getContext().obtainStyledAttributes(

attrs,?R.styleable.TimeLineMarker,?0,?0);

mMarkerSize?=?a.getDimensionPixelSize(

R.styleable.TimeLineMarker_markerSize,

mMarkerSize);

mLineSize?=?a.getDimensionPixelSize(

R.styleable.TimeLineMarker_lineSize,

mLineSize);

mBeginLine?=?a.getDrawable(

R.styleable.TimeLineMarker_beginLine);

mEndLine?=?a.getDrawable(

R.styleable.TimeLineMarker_endLine);

mMarkerDrawable?=?a.getDrawable(

R.styleable.TimeLineMarker_marker);

a.recycle();

if?(mBeginLine?!=?null)

mBeginLine.setCallback(this);

if?(mEndLine?!=?null)

mEndLine.setCallback(this);

if?(mMarkerDrawable?!=?null)

mMarkerDrawable.setCallback(this);

}

Drawable 的位置與大小初始化

屬性啥的有了,具體的Drawable 也有了,要顯示的地方調(diào)用也是OK了;但是如果沒有進(jìn)行進(jìn)行具體的位置調(diào)整這一切也都沒有意義。@Override

protected?void?onSizeChanged(int?w,?int?h,?int?oldw,?int?oldh)?{

super.onSizeChanged(w,?h,?oldw,?oldh);

initDrawableSize();

}

private?void?initDrawableSize()?{

int?pLeft?=?getPaddingLeft();

int?pRight?=?getPaddingRight();

int?pTop?=?getPaddingTop();

int?pBottom?=?getPaddingBottom();

int?width?=?getWidth();

int?height?=?getHeight();

int?cWidth?=?width?-?pLeft?-?pRight;

int?cHeight?=?height?-?pTop?-?pBottom;

Rect?bounds;

if?(mMarkerDrawable?!=?null)?{

//?Size

int?markerSize?=?Math.min(mMarkerSize,?Math.min(cWidth,?cHeight));

mMarkerDrawable.setBounds(pLeft,?pTop,

pLeft?+?markerSize,?pTop?+?markerSize);

bounds?=?mMarkerDrawable.getBounds();

}?else?{

bounds?=?new?Rect(pLeft,?pTop,?pLeft?+?cWidth,?pTop?+?cHeight);

}

int?halfLineSize?=?mLineSize?>>?1;

int?lineLeft?=?bounds.centerX()?-?halfLineSize;

if?(mBeginLine?!=?null)?{

mBeginLine.setBounds(lineLeft,?0,?lineLeft?+?mLineSize,?bounds.top);

}

if?(mEndLine?!=?null)?{

mEndLine.setBounds(lineLeft,?bounds.bottom,?lineLeft?+?mLineSize,?height);

}

}

initDrawableSize 方法進(jìn)行具體的運(yùn)算,而運(yùn)算的時(shí)間點(diǎn)就是當(dāng)控件的大小改變(onSizeChanged)的時(shí)候。

在初始化中采用了一定的投機(jī)取巧;這里利用了上內(nèi)邊距與下內(nèi)邊距分別作為上線條與下線條的長度;而線條與中間的標(biāo)識都采用了水平距中。

其他設(shè)置方法public?void?setLineSize(int?lineSize)?{

if?(mLineSize?!=?lineSize)?{

this.mLineSize?=?lineSize;

initDrawableSize();

invalidate();

}

}

public?void?setMarkerSize(int?markerSize)?{

if?(this.mMarkerSize?!=?markerSize)?{

mMarkerSize?=?markerSize;

initDrawableSize();

invalidate();

}

}

public?void?setBeginLine(Drawable?beginLine)?{

if?(this.mBeginLine?!=?beginLine)?{

this.mBeginLine?=?beginLine;

if?(mBeginLine?!=?null)?{

mBeginLine.setCallback(this);

}

initDrawableSize();

invalidate();

}

}

public?void?setEndLine(Drawable?endLine)?{

if?(this.mEndLine?!=?endLine)?{

this.mEndLine?=?endLine;

if?(mEndLine?!=?null)?{

mEndLine.setCallback(this);

}

initDrawableSize();

invalidate();

}

}

public?void?setMarkerDrawable(Drawable?markerDrawable)?{

if?(this.mMarkerDrawable?!=?markerDrawable)?{

this.mMarkerDrawable?=?markerDrawable;

if?(mMarkerDrawable?!=?null)?{

mMarkerDrawable.setCallback(this);

}

initDrawableSize();

invalidate();

}

}

在設(shè)置中,首先判斷是否更改,如果更改那么就更新并重新計(jì)算位置;隨后刷新界面。到這里,控件差不多準(zhǔn)備OK了,其中還有很多可以完善的地方,比如加上快捷設(shè)置顏色什么的,也可以加上大小計(jì)算的東西。同時(shí)還可以加上時(shí)間線是水瓶還是垂直等等。在這里就不累贅介紹哪些了。下面來看看如何使用。

使用

XML布局

ITEM布局item_time_line.xml<?xml ?version="1.0"?encoding="utf-8"?>

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal"

android:paddingLeft="@dimen/lay_16"

android:paddingRight="@dimen/lay_16"

tools:ignore="MissingPrefix">

android:id="@+id/item_time_line_mark"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:paddingBottom="@dimen/lay_16"

android:paddingLeft="@dimen/lay_4"

android:paddingRight="@dimen/lay_4"

android:paddingTop="@dimen/lay_16"

app:beginLine="@color/black_alpha_32"

app:endLine="@color/black_alpha_32"

app:lineSize="2dp"

app:marker="@drawable/ic_timeline_default_marker"

app:markerSize="24dp"?/>

android:id="@+id/item_time_line_txt"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:paddingBottom="@dimen/lay_16"

android:paddingLeft="@dimen/lay_4"

android:paddingRight="@dimen/lay_4"

android:paddingTop="@dimen/lay_16"

android:textColor="@color/grey_600"

android:textSize="@dimen/font_16"?/>

在這里我們之間使用順序布局,左邊是TimelIne控件,右邊是一個(gè)簡單的字體控件,具體使用中可以細(xì)化一些。?在TImeLine控件中我們的Mark是使用的drawable/ic_timeline_default_marker;這個(gè)就是一個(gè)簡單的圓圈而已;對于自己美化可以使用一張圖片代替或者更加復(fù)雜的布局;當(dāng)然上面的線條就更加簡單了,就直接使用顏色代替。<?xml ?version="1.0"?encoding="utf-8"?>

android:shape="oval">

android:width="1dp"

android:color="@color/black_alpha_32"?/>

主界面XML RecyclerView

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context=".MainActivity">

android:id="@+id/time_line_recycler"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:clickable="true"

android:fadeScrollbars="true"

android:fadingEdge="none"

android:focusable="true"

android:focusableInTouchMode="true"

android:overScrollMode="never"

android:scrollbarSize="2dp"

android:scrollbarThumbVertical="@color/cyan_500"

android:scrollbars="vertical"?/>

在這里就是加上了一個(gè)RecyclerView 控件在主界面就OK。

Java代碼部分

在開始之前先來看看我們的文件具體有些神馬。

widget中就是具體的自定義控件,model是具體的數(shù)據(jù)模型,adapter部分,這里有一個(gè)Recyclerview的adapter文件,以及一個(gè)具體的Item TimeLineViewHolder,當(dāng)然在這里還定義了一個(gè)ItemType類,該類用來標(biāo)示每個(gè)Item的類型,比如頭部,第一個(gè),普通,最后一個(gè),底部等等。

TimeLineModel.javapackage?net.qiujuer.example.timeline.model;

/**

*?Created?by?qiujuer

*?on?15/8/23.

*/

public?class?TimeLineModel?{

private?String?name;

private?int?age;

public?TimeLineModel()?{

}

public?TimeLineModel(String?name,?int?age)?{

this.name?=?name;

this.age?=?age;

}

public?int?getAge()?{

return?age;

}

public?String?getName()?{

return?name;

}

public?void?setAge(int?age)?{

this.age?=?age;

}

public?void?setName(String?name)?{

this.name?=?name;

}

}

一個(gè)名字,一個(gè)年齡也就OK。

ItemType.javapackage?net.qiujuer.example.timeline.adapter;

/**

*?Created?by?qiujuer

*?on?15/8/23.

*/

public?class?ItemType?{

public?final?static?int?NORMAL?=?0;

public?final?static?int?HEADER?=?1;

public?final?static?int?FOOTER?=?2;

public?final?static?int?START?=?4;

public?final?static?int?END?=?8;

public?final?static?int?ATOM?=?16;

}

分別定義了幾個(gè)靜態(tài)值,分別代表普通、頭部、底部、開始、結(jié)束、原子;當(dāng)然其中有些可以不用定義。

TimeLineViewHolder.javapackage?net.qiujuer.example.timeline.adapter;

import?android.support.v7.widget.RecyclerView;

import?android.view.View;

import?android.widget.TextView;

import?net.qiujuer.example.timeline.R;

import?net.qiujuer.example.timeline.model.TimeLineModel;

import?net.qiujuer.example.timeline.widget.TimeLineMarker;

/**

*?Created?by?qiujuer

*?on?15/8/23.

*/

public?class?TimeLineViewHolder?extends?RecyclerView.ViewHolder?{

private?TextView?mName;

public?TimeLineViewHolder(View?itemView,?int?type)?{

super(itemView);

mName?=?(TextView)?itemView.findViewById(R.id.item_time_line_txt);

TimeLineMarker?mMarker?=?(TimeLineMarker)?itemView.findViewById(R.id.item_time_line_mark);

if?(type?==?ItemType.ATOM)?{

mMarker.setBeginLine(null);

mMarker.setEndLine(null);

}?else?if?(type?==?ItemType.START)?{

mMarker.setBeginLine(null);

}?else?if?(type?==?ItemType.END)?{

mMarker.setEndLine(null);

}

}

public?void?setData(TimeLineModel?data)?{

mName.setText("Name:"?+?data.getName()?+?"?Age:"?+?data.getAge());

}

}

該文件為RecyclerView 的Adapter中每個(gè)Item需要實(shí)現(xiàn)的Holder類。?在該類中,我們在構(gòu)造函數(shù)中需要傳入一個(gè)根View同時(shí)傳入一個(gè)當(dāng)然item的狀態(tài)。?隨后使用find….找到控件,在這里我們把TextView保存起來,而TimeLineView找到后直接進(jìn)行初始化設(shè)置。?根據(jù)傳入的ItemType來判斷是否是第一個(gè),最后一個(gè),以及原子;然后設(shè)置TimeLineView的屬性。?在下面的setData方法中我們顯示具體的Model數(shù)據(jù)。

TimeLineAdapter.java

適配器部分,我們需要做的工作是;根據(jù)具體的數(shù)據(jù)渲染上對應(yīng)的界面就OK。package?net.qiujuer.example.timeline.adapter;

import?android.support.v7.widget.RecyclerView;

import?android.view.LayoutInflater;

import?android.view.View;

import?android.view.ViewGroup;

import?net.qiujuer.example.timeline.R;

import?net.qiujuer.example.timeline.model.TimeLineModel;

import?java.util.List;

/**

*?Created?by?qiujuer

*?on?15/8/23.

*/

public?class?TimeLineAdapter?extends?RecyclerView.Adapter?{

private?List?mDataSet;

public?TimeLineAdapter(List?models)?{

mDataSet?=?models;

}

@Override

public?int?getItemViewType(int?position)?{

final?int?size?=?mDataSet.size()?-?1;

if?(size?==?0)

return?ItemType.ATOM;

else?if?(position?==?0)

return?ItemType.START;

else?if?(position?==?size)

return?ItemType.END;

else?return?ItemType.NORMAL;

}

@Override

public?TimeLineViewHolder?onCreateViewHolder(ViewGroup?viewGroup,?int?viewType)?{

//?Create?a?new?view.

View?v?=?LayoutInflater.from(viewGroup.getContext())

.inflate(R.layout.item_time_line,?viewGroup,?false);

return?new?TimeLineViewHolder(v,?viewType);

}

@Override

public?void?onBindViewHolder(TimeLineViewHolder?timeLineViewHolder,?int?i)?{

timeLineViewHolder.setData(mDataSet.get(i));

}

@Override

public?int?getItemCount()?{

return?mDataSet.size();

}

}在這里需要著重說一下:我復(fù)寫了getItemViewType方法;在該方法中我們需要設(shè)置對應(yīng)的Item的類型;在這里傳入的是item的坐標(biāo),需要返回的是item的具體狀態(tài),該狀態(tài)標(biāo)示是int類型;在這里我使用的是ItemType的靜態(tài)屬性。

該方法會在調(diào)用onCreateViewHolder方法之前調(diào)用;而onCreateViewHolder方法中的第二個(gè)參數(shù)int值也就是從getItemViewType之中來;所以我們可以在這里進(jìn)行對應(yīng)的數(shù)據(jù)狀態(tài)標(biāo)示。

而在onCreateViewHolder方法中我們返回一個(gè):TimeLineViewHolder就OK,隨后在onBindViewHolder方法中進(jìn)行數(shù)據(jù)初始化操作。

MainActivity.java

上面所有都準(zhǔn)備好了,下面就進(jìn)行具體的顯示。?在這里就只貼出核心代碼了;篇幅也是有些長。private?RecyclerView?mRecycler;

@Override

protected?void?onCreate(Bundle?savedInstanceState)?{

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mRecycler?=?(RecyclerView)?findViewById(R.id.time_line_recycler);

initRecycler();

}

private?void?initRecycler()?{

LinearLayoutManager?layoutManager?=?new?LinearLayoutManager(this);

layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

TimeLineAdapter?adapter?=?new?TimeLineAdapter(getData());

mRecycler.setLayoutManager(layoutManager);

mRecycler.setAdapter(adapter);

}

private?List?getData()?{

List?models?=?new?ArrayList();

models.add(new?TimeLineModel("XiaoMing",?21));

models.add(new?TimeLineModel("XiaoFang",?20));

models.add(new?TimeLineModel("XiaoHua",?25));

models.add(new?TimeLineModel("XiaoA",?22));

models.add(new?TimeLineModel("XiaoNiu",?23));

return?models;

}

在這里就是傻瓜的操作了,流程就是準(zhǔn)備好對應(yīng)的數(shù)據(jù),裝進(jìn)Adapter,準(zhǔn)備好對應(yīng)的布局方式,然后都設(shè)置到RecyclerView中就OK。

效果

來看看具體的效果:

效果雖然簡單,但是也算是五臟具全;其中無非就是控件的自定義。這個(gè)自定義是可以擴(kuò)展的,大家可以擴(kuò)展為水平方向試試。

代碼

寫在最后

文章的開始截屏來源于:最近沒事兒搗鼓了一個(gè)APP[UPMiss],一個(gè)簡單的生日,紀(jì)念日提醒軟件;歡迎大家嘗鮮。

{UPMiss} 思念你的夏天?下載地址:百度?這個(gè)審核有問題,明明沒有支付的東西,結(jié)果說有支付的SDK存在,不得不說百度的自動審核有很大漏洞。

豌豆莢?新版2.0還在審核中!

========================================================?作者:qiujuer

總結(jié)

以上是生活随笔為你收集整理的android 日程安排view,RecyclerView 列表控件中简单实现时间线的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。