网站备案到公司,炫酷的动画网站,乐陵seo优化信,手机蓝牙app开发教程时间时间#xff0c;时间#xff0c;时间啊#xff1b;走慢一点吧#xff5e;看见很多软件中都有时间线的东西#xff0c;貌似天气啊#xff0c;旅游啊什么的最多了#xff1b;具体实现方式很多#xff0c;在本篇文章中讲解一种自定义View封装的方式。效果先来看看效果…时间时间时间时间啊走慢一点吧看见很多软件中都有时间线的东西貌似天气啊旅游啊什么的最多了具体实现方式很多在本篇文章中讲解一种自定义View封装的方式。效果先来看看效果。分析软件中可以看见前面的时间线也就是线条加上圆圈组成当然这里的圆圈与线条也都是可以随意换成其他的比如图片等等。当然这里最简单的来说是上面一个线条然后一个圆圈然后下面一个线条上线条在第一条数据时不做显示下线条在最后一条数据时不做显示。这里自定义布局部分也就是把旁边的线条与圆圈封装到一起并使用简单的方法来控制是否显示。 当封装好了后与旁边的文字部分也就是水瓶方向的线性布局了然后设置为每一个的RecyclerView 的Item的布局也就完成了。控件控件很简单首先我们继承View取名为 TimeLineMarker 就OK。Attrs 属性开始控件之前先准备好需要的属性。?xml version1.0 encodingutf-8?在这里也就准备了线条的大小、开始线条、结束线条、中间标示部分及大小。属性与现实private int mMarkerSize 24;private int mLineSize 12;private Drawable mBeginLine;private Drawable mEndLine;private Drawable mMarkerDrawable;Overrideprotected 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);}两个大小属性3个具体的Drawable然后在onDraw方法中进行具体的显示也就OK。构造与属性初始化在上面我们定义了属性在这里我们在构造函数中获取XML所设置的属性。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 attributesfinal 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 也有了要显示的地方调用也是OK了但是如果没有进行进行具体的位置调整这一切也都没有意义。Overrideprotected 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) {// Sizeint 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 方法进行具体的运算而运算的时间点就是当控件的大小改变(onSizeChanged)的时候。在初始化中采用了一定的投机取巧这里利用了上内边距与下内边距分别作为上线条与下线条的长度而线条与中间的标识都采用了水平距中。其他设置方法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();}}在设置中首先判断是否更改如果更改那么就更新并重新计算位置随后刷新界面。到这里控件差不多准备OK了其中还有很多可以完善的地方比如加上快捷设置颜色什么的也可以加上大小计算的东西。同时还可以加上时间线是水瓶还是垂直等等。在这里就不累赘介绍哪些了。下面来看看如何使用。使用XML布局ITEM布局item_time_line.xml?xml version1.0 encodingutf-8?xmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:orientationhorizontalandroid:paddingLeftdimen/lay_16android:paddingRightdimen/lay_16tools:ignoreMissingPrefixandroid:idid/item_time_line_markandroid:layout_widthwrap_contentandroid:layout_heightmatch_parentandroid:paddingBottomdimen/lay_16android:paddingLeftdimen/lay_4android:paddingRightdimen/lay_4android:paddingTopdimen/lay_16app:beginLinecolor/black_alpha_32app:endLinecolor/black_alpha_32app:lineSize2dpapp:markerdrawable/ic_timeline_default_markerapp:markerSize24dp /android:idid/item_time_line_txtandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:layout_gravitycenterandroid:paddingBottomdimen/lay_16android:paddingLeftdimen/lay_4android:paddingRightdimen/lay_4android:paddingTopdimen/lay_16android:textColorcolor/grey_600android:textSizedimen/font_16 /在这里我们之间使用顺序布局左边是TimelIne控件右边是一个简单的字体控件具体使用中可以细化一些。 在TImeLine控件中我们的Mark是使用的drawable/ic_timeline_default_marker这个就是一个简单的圆圈而已对于自己美化可以使用一张图片代替或者更加复杂的布局当然上面的线条就更加简单了就直接使用颜色代替。?xml version1.0 encodingutf-8?android:shapeovalandroid:width1dpandroid:colorcolor/black_alpha_32 /主界面XML RecyclerViewxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:paddingBottomdimen/activity_vertical_marginandroid:paddingLeftdimen/activity_horizontal_marginandroid:paddingRightdimen/activity_horizontal_marginandroid:paddingTopdimen/activity_vertical_margintools:context.MainActivityandroid:idid/time_line_recyclerandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:clickabletrueandroid:fadeScrollbarstrueandroid:fadingEdgenoneandroid:focusabletrueandroid:focusableInTouchModetrueandroid:overScrollModeneverandroid:scrollbarSize2dpandroid:scrollbarThumbVerticalcolor/cyan_500android:scrollbarsvertical /在这里就是加上了一个RecyclerView 控件在主界面就OK。Java代码部分在开始之前先来看看我们的文件具体有些神马。widget中就是具体的自定义控件model是具体的数据模型adapter部分这里有一个Recyclerview的adapter文件以及一个具体的Item TimeLineViewHolder当然在这里还定义了一个ItemType类该类用来标示每个Item的类型比如头部第一个普通最后一个底部等等。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;}}一个名字一个年龄也就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;}分别定义了几个静态值分别代表普通、头部、底部、开始、结束、原子当然其中有些可以不用定义。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中每个Item需要实现的Holder类。 在该类中我们在构造函数中需要传入一个根View同时传入一个当然item的状态。 随后使用find….找到控件在这里我们把TextView保存起来而TimeLineView找到后直接进行初始化设置。 根据传入的ItemType来判断是否是第一个最后一个以及原子然后设置TimeLineView的属性。 在下面的setData方法中我们显示具体的Model数据。TimeLineAdapter.java适配器部分我们需要做的工作是根据具体的数据渲染上对应的界面就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;}Overridepublic 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;}Overridepublic 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);}Overridepublic void onBindViewHolder(TimeLineViewHolder timeLineViewHolder, int i) {timeLineViewHolder.setData(mDataSet.get(i));}Overridepublic int getItemCount() {return mDataSet.size();}}在这里需要着重说一下我复写了getItemViewType方法在该方法中我们需要设置对应的Item的类型在这里传入的是item的坐标需要返回的是item的具体状态该状态标示是int类型在这里我使用的是ItemType的静态属性。该方法会在调用onCreateViewHolder方法之前调用而onCreateViewHolder方法中的第二个参数int值也就是从getItemViewType之中来所以我们可以在这里进行对应的数据状态标示。而在onCreateViewHolder方法中我们返回一个TimeLineViewHolder就OK随后在onBindViewHolder方法中进行数据初始化操作。MainActivity.java上面所有都准备好了下面就进行具体的显示。 在这里就只贴出核心代码了篇幅也是有些长。private RecyclerView mRecycler;Overrideprotected 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;}在这里就是傻瓜的操作了流程就是准备好对应的数据装进Adapter准备好对应的布局方式然后都设置到RecyclerView中就OK。效果来看看具体的效果效果虽然简单但是也算是五脏具全其中无非就是控件的自定义。这个自定义是可以扩展的大家可以扩展为水平方向试试。代码写在最后文章的开始截屏来源于最近没事儿捣鼓了一个APPUPMiss一个简单的生日纪念日提醒软件欢迎大家尝鲜。UPMiss 思念你的夏天 下载地址百度 这个审核有问题明明没有支付的东西结果说有支付的SDK存在不得不说百度的自动审核有很大漏洞。豌豆荚 新版2.0还在审核中 作者qiujuer