preface

  • Timeline UI is very common in Android development, as shown below:

  • Reserve knowledge: 1. Custom view foundation 2.RecyclerView use 3. Custom RecyclerView ItemDecoration

The specific implementation

1. The final effect is as follows:

2. Implementation idea

  • Use RecyclerView, custom RecyclerView ItemDecoration
  • (getItemOffsets(); onDraw()
  • RecyclerView.Adapter, binding data

3. Detailed design

4. Implementation

  • Introduce RecyclerView dependency package
dependencies {
     ..........
    api 'com. Android. Support: recyclerview - v7:28.0.0'
}
Copy the code
  • Used in layout files
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="horizontal"
        />


</RelativeLayout>
Copy the code
  • Setting the Item Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <TextView
        android:id="@+id/item_title"
        android:text="New Text"
        android:textSize="15sp"
        android:layout_marginLeft="30dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New Text"
        android:layout_marginLeft="30dp"
        android:textSize="15sp"
        android:id="@+id/item_text"
        android:layout_below="@+id/item_title"
        />

</LinearLayout>
Copy the code
  • Implement RecyclerView. Adapter
public class MyAdapter extends RecyclerView.Adapter { private LayoutInflater inflater; private ArrayList<HashMap<String,Object>> listitem; Public MyAdapter(Context Context,ArrayList<HashMap<String, Object>> listitem) { this.inflater = LayoutInflater.from(context); this.listitem = listitem; } class ViewHolder extends RecyclerView.ViewHolder{ private TextView title,text; public ViewHolder(@NonNull View itemView) { super(itemView); title = itemView.findViewById(R.id.item_title); text = itemView.findViewById(R.id.item_text); } public TextViewgetTitle() {
            return title;
        }

        public TextView getText() {
            return text;
        }


    }



    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        return new ViewHolder(inflater.inflate(R.layout.list_cell,null));
        //绑定item布局
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
          //绑定数据到ViewHolder
        ViewHolder  vh = (ViewHolder) viewHolder;
        vh.title.setText((CharSequence) listitem.get(i).get("ItemTitle"));
        vh.text.setText((CharSequence) listitem.get(i).get("ItemText"));
    }

    @Override
    public int getItemCount() {
        returnlistitem.size(); }}Copy the code
  • Custom RecyclerView ItemDecoration
Public class DividerItemDecoration extends RecyclerView. ItemDecoration {/ / pivot private final brush Paint mPaint; // Private final Paint mPaint1; // Private final Paint mPaint2; //itemView Left upper offset private int itemView_leftinterval; private int itemView_topintervarl; Private int circle_radius; private final Bitmap mIcon; Public DividerItemDecoration(Context Context){mPaint = new Paint(); mPaint.setColor(Color.RED); // Set the Paint color to red mPaint1 = new Paint(); mPaint1.setColor(Color.BLUE); mPaint1.setTextSize(30); MPaint2 = new Paint(); mPaint2.setColor(Color.BLUE); mPaint2.setTextSize(15); itemView_leftinterval = 200; ItemView_topintervarl = 50; // The upper offset length is 50 circle_radius = 10; / / shaft radius to 10 mIcon = BitmapFactory decodeResource (context) getResources (), R.m ipmap. Logo); } @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); Outrect. set(itemView_leftinterval,itemView_topintervarl,0,0); } @Override public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.onDraw(c, parent, state); Int childCount = parent.getChildCount(); // Walk through each item, get their location information, and draw the corresponding dividing linefor(int i=0; i<childCount; i++){ View view = parent.getChildAt(i); // Get each item object /** * draw axis point */ / axis point = circle = center (x,y)float centerX = view.getLeft() - itemView_leftinterval/3;
            floatcenterY = view.getTop() - itemView_topintervarl+(itemView_topintervarl+view.getHeight()/2); C.paint circle (centerX,centerY,circle_radius,mPaint); c.drawBitmap(mIcon,centerX-circle_radius,centerY-circle_radius,mPaint); / draw half axis * * * * / / / endpoint coordinates (x, y)float upLine_up_x = centerX;
            floatupLine_up_y =view.getTop()-itemView_topintervarl; // lower endpoint (x,y)float upLine_down_x = centerX;
            floatupLine_down_y = centerY-circle_radius; c.drawLine(upLine_up_x,upLine_up_y,upLine_down_x,upLine_down_y,mPaint); / / draw the second half of the axis/draw the second half of the axis of * * * * / / / endpoint coordinates (x, y)float bottomLine_up_x = centerX;
            floatbottom_up_y = centerY + circle_radius; // lower endpoint (x,y)float bottomLine_bottom_x = centerX;
            floatbottomLine_bottom_y = view.getBottom(); BottomLine_up_x, bottom_up_Y, bottomLine_bottom_x, bottomLine_bottom_y, mPaint); / text drawn on the left time * * * * / int index = parent. GetChildAdapterPosition (view); // Draw the starting position of the time textfloat Text_x = view.getLeft()-itemView_leftinterval*5/6;
          floatText_y = upLine_down_y; // Switch (index){case0: // Set the drawing date c.rawtext ("" ",Text_x,Text_y,mPaint1);
                    c.drawText("2018.4.03",Text_x+5,Text_y+20,mPaint2);
                    break;
                case1: // Set the drawing date c.rawtext ("" ",Text_x,Text_y,mPaint1);
                    c.drawText("2018.4.03",Text_x+5,Text_y+20,mPaint2);
                    break;
                case2: // Set the drawing date c.rawtext ("" ",Text_x,Text_y,mPaint1);
                    c.drawText("2018.4.03",Text_x+5,Text_y+20,mPaint2);
                    break;
                case3: // Set the drawing date c.rawtext ("" ",Text_x,Text_y,mPaint1);
                    c.drawText("2018.4.03",Text_x+5,Text_y+20,mPaint2);
                    break;
                case4: // Set the drawing date c.rawtext ("" ",Text_x,Text_y,mPaint1);
                    c.drawText("2018.4.03",Text_x+5,Text_y+20,mPaint2);
                    break;
                case5: // Set the drawing date c.rawtext ("" ",Text_x,Text_y,mPaint1);
                    c.drawText("2018.4.03",Text_x+5,Text_y+20,mPaint2);
                    break;
                    default:
                        c.drawText("Received",Text_x,Text_y,mPaint1); }}}}Copy the code
  • Initialize data, bind RecyclerView
public class MainActivity extends AppCompatActivity {

    private ArrayList<HashMap<String, Object>> itemlist;
    private RecyclerView rl;

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

    private void initData() {
        itemlist = new ArrayList<HashMap<String, Object>>();
        HashMap<String, Object> map1 = new HashMap<String, Object>();
        HashMap<String, Object> map2 = new HashMap<String, Object>();
        HashMap<String, Object> map3 = new HashMap<String, Object>();
        HashMap<String, Object> map4 = new HashMap<String, Object>();
        HashMap<String, Object> map5 = new HashMap<String, Object>();
        HashMap<String, Object> map6 = new HashMap<String, Object>();


        map1.put("ItemTitle"."Issued by Guangzhou Company, China");
        map1.put("ItemText"."From: Mirkady Culture Company");
        itemlist.add(map1);

        map2.put("ItemTitle"."Sf Express has earned revenue");
        map2.put("ItemText"."Waiting for transit");
        itemlist.add(map2);

        map3.put("ItemTitle"."Sf Express Forwarding");
        map3.put("ItemText"."Next stop, China.");
        itemlist.add(map3);

        map4.put("ItemTitle"."Sf Express Has earned revenue");
        map4.put("ItemText"."Next stop: Jiangsu University of Science and Technology");
        itemlist.add(map4);

        map5.put("ItemTitle"."China SF Express Delivery");
        map5.put("ItemText"."Waiting for delivery");
        itemlist.add(map5);

        map6.put("ItemTitle"."Jiangsu University of Science and Technology has signed for it");
        map6.put("ItemText"."收件人:darryrzhong");
        itemlist.add(map6);

    }

    private void initView() { rl = findViewById(R.id.my_recycler_view); LinearLayoutManager manager = new LinearLayoutManager(this); rl.setLayoutManager(manager); // Can be set to change the width and height of RecyclerView when it is known that changes in the Adapter Item will not affect the width and height of RecyclerViewtrueMake RecyclerView avoid recalculating. rl.setHasFixedSize(true); rl.addItemDecoration(new DividerItemDecoration(this)); MyAdapter adapter = new MyAdapter(this, itemList); rl.setAdapter(adapter); }}Copy the code

At this point, custom RecyclerView is completed.

Reference article:

Android custom View Combat series: timeline

Welcome to darryrzhong, more dry goods waiting for you to get yo.

A little red heart, please! Because your encouragement is the biggest power that I write!

Please pay attention to more wonderful articles

  • Personal blog: Darryrzhong
  • The Denver nuggets
  • Jane’s book
  • SegmentFault
  • Moocs Notebook