📜 ⬆️ ⬇️

We introduce material design

It's time to switch to Lollipop, friends. No matter how funny it sounds.

image

Just yesterday, we in Surfingbird updated the design of the application and today, on the fresh tracks, I would like to share my impressions of the transition to the material design.

')
Preparatory stage.

To minimize the number of problems, it is better to update all)



Implement RecyclerView

RecyclerView is a new ViewGroup component that replaces the List / GridView. But he is not their descendant; rather, it is an alternative branch of evolution. On the one hand, it is a much more flexible and more efficiently working component, on the other - there are no boxes in it, or some other things that we are used to in List / GridView (dividers, quick scroll, selectors, headers, etc.) P.).
Firstly, according to subjective sensations, scrolling became smoother than when using the listview + viewholder, and secondly, a lot of beautiful pieces appeared, so the game is definitely worth it.

Go to this component is very simple. We drop the corresponding sdk â–¸ extras â–¸ android â–¸ support â–¸ v7 â–¸ recyclerview â–¸ libsâ–¸ android-support-v7-recyclerview.jar / into the libraries in the godless gradle or whatever you use.

1. We update the adapter, if you have already used the view-holder pattern, then everything is familiar

Replace the BaseAdapter (or whatever you had) with RecyclerView.Adapter <AdapterMain.ViewHolder>

In onCreateViewHolder - parsim layout

@Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View view = layoutInflater.inflate(R.layout.main_adapter_griditem, null); return new ViewHolder(view); } 


where the ViewHolder itself is a familiar stub

  class ViewHolder extends RecyclerView.ViewHolder{ private ImageView stgvImageView; public ViewHolder(View holderView) { super(holderView); stgvImageView = (ImageView) holderView.findViewById(R.id.stgvImageView); } } 


and transfer the view filling logic from getView to onBindViewHolder (referring to the holder - holder.stgvImageView, etc.)

Remove unnecessary methods like getItem

2. Replace ListView with RecyclerView

  public RecyclerView gridView;//  Grid/ListView public AdapterMain adapterMain; public ArrayList<Site> rows; //   recycleview.          //GridLayoutManager (Grid)  LinearLayoutManager (List) public StaggeredGridLayoutManager mLayoutManager; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { aq = new AQuery(getActivity()); //     final LinearLayout linearLayout = new LinearLayout(getActivity()); linearLayout.setOrientation(LinearLayout.VERTICAL); linearLayout.setGravity(Gravity.CENTER); gridView = new RecyclerView(getActivity()); gridView.setHasFixedSize(true); mLayoutManager = new StaggeredGridLayoutManager(UtilsScreen.getDisplayColumns(getActivity()),StaggeredGridLayoutManager.VERTICAL); //   .    .  gridView.setLayoutManager(mLayoutManager); gridView.setItemAnimator(new DefaultItemAnimator()); //     divider //gridView.addItemDecoration(new DividerItemDecoration(getActivity())); //    //gridView.setSmoothScrollbarEnabled(true); //gridView.setDivider(new ColorDrawable(this.getResources().getColor(R.color.gray_divider))); //gridView.setDividerHeight(UtilsScreen.dpToPx(8)); rows = new ArrayList<Site>(); linearLayout.addView(gridView); return linearLayout; } 


3. We continue the conversation.

Work with the adapter has not changed.

  @Override public void onViewCreated(View view,Bundle savedInstanceState) { super.onViewCreated(view,savedInstanceState); adapterMain = new AdapterMain(getActivity(),rows); gridView.setAdapter(adapterMain); gridView.setOnScrollListener(onScroll); } 


The method of disconnecting the adapter at the time of the change (DataSetInvalidated) became unnecessary, the change notification remained unchanged

  adapterMain.notifyDataSetChanged(); if (page == 1) gridView.scrollToPosition(0);//        


The method for calculating the last visible element has changed (to automatically load the next batch). I suppose that this logic is better to be transferred to the adapter, but, if there is very little time, then it is possible, for example:

  gridView.setOnScrollListener(onScroll); //--- private RecyclerView.OnScrollListener onScroll = new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int[] visibleItems = ((StaggeredGridLayoutManager) gridView.getLayoutManager()).findLastVisibleItemPositions(null); int lastitem=0; for (int i:visibleItems) { lastitem = Math.max(lastitem,i); } if (lastitem>0 && lastitem>adapterMain.data.size()-5 && !isRunning) { if (!internetIsOver) { refresh(); } } } }; 


In general, scrolling has become lower-level, now you can get information directly and in this method where and how much is scrolled (forgive my English)

At this place you have to earn everything. If, for example, you need to add dividers, you can add them by overlapping the DividerItemDecoration class, for example: (vertical dividers)
(Akhtung, you know kopipasta from which site)

  public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; private Drawable mDivider; private int offset = 0; public DividerItemDecoration(Context context) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); offset = UtilsScreen.dpToPx(16); a.recycle(); } @Override public void onDraw(Canvas c, RecyclerView parent) { drawVertical(c, parent); } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + offset;//mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { outRect.set(0, 0, 0, offset);//mDivider.getIntrinsicHeight()); } } 


But don't rush it! Because beautiful Cards have appeared!

Implement CardView

I remember when I was still a very young android developer, I got interested and all went nuts. We spent hours looking at how they implemented variable height cards, floating buttons (or was it in Path?), It doesn't matter. Now you can get a good looking card (including variable height and just as in interest) literally a couple of lines of code.

We connect cardview as library project / we register a magic line in the build system, we throw jar, not forgetting to update the version of librari support.

In fact, the cards are a frame around your layout with tenyushkami and skruglyashkami, so just frame them with your layout:

  <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" android:id="@+id/card_view" android:layout_gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content" card_view:contentPadding="8dp" card_view:cardBackgroundColor="@color/primary_bgr" card_view:cardUseCompatPadding="true" card_view:cardCornerRadius="4dp"> <RelativeLayout android:id="@+id/articleLayout" android:background="@color/primary_bgr" android:layout_width="match_parent" android:layout_height="wrap_content"> //--- 


Done, Milord!

Now, let's say, for the tablet version we set the display in two columns, and for the phones in one:
(Akhtung, you know kopipasta from which site)

  public static boolean isTablet(Context context) { boolean xlarge = ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == 4); boolean large = ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE); return (xlarge || large); } public static int getDisplayColumns(Activity activity) { int columnCount = 1; if (isTablet(activity)) { columnCount = 2; } return columnCount; } 


And we set a different display format for different devices:

  mLayoutManager = new StaggeredGridLayoutManager(UtilsScreen.getDisplayColumns(getActivity()),StaggeredGridLayoutManager.VERTICAL); 


It should look like this:


Some nuances:



Result

The developer's eye is “zamylen”, hard to say it turned out well or so-so. For some reason, I expected more, to be honest. Dynamically falling shadows when scrolling, for example, more magic. But in general, everything turned out a little fresher. Although, of course, we are not fully ollipolitic. You can see the result in the market .

I probably forgot something. Share the nuances, recipes and tips for switching to lollipop in the comments. The topic is relevant, it will be useful and interesting for all of us.

Source: https://habr.com/ru/post/244387/


All Articles