Reprint please indicate the source: www.jianshu.com/p/5cb2586ac… This article is from :Jlanglang

# introduction:

Following the MVP experience four made a lot of changes. There are a lot of difficulties during this period. Compare Google’s thinking on activities and appcompatactivities and divide the original code into two modules. One corresponds to FragmentActivity and the other corresponds to AppcompatActivity, which is no longer written together.

You cannot use the AppCompat control without relying on the AppCompat-v7 package. <__>

#1.Toolbar encapsulation ##### imagines many scenarios. Dead n brain cells, resulting in the structure of:

# # (1). Appcompat style:

<? xml version="1.0" encoding="utf-8"? > <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:theme="@style/BaseAppTheme">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"/>
    <FrameLayout
        android:id="@+id/templet_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        />
</android.support.design.widget.CoordinatorLayout>
Copy the code

# # # the Toolbar template

<? xml version="1.0" encoding="utf-8"? > <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    app:contentScrim="? attr/colorPrimary"
    >

    <android.support.v7.widget.Toolbar
        android:id="@+id/tl_costom"
        style="@style/base_toolbar"
        android:layout_height="? actionBarSize"
        app:layout_collapseMode="pin"
        app:popupTheme="@style/popup_theme"
        app:theme="@style/toolbar_theme"
        />

</android.support.design.widget.CollapsingToolbarLayout>
Copy the code

Design idea: 1. The outermost layer uses CoordinatorLayout, providing animation, linkage features. 2. Use AppBarLayout, can add the Toolbar, and other controls, you can use Tablayout, CollapsingToolbarLayout, toolbars, etc. 3. The main content uses FrameLayout, which can be extended to encapsulate loadingView, etc.

##(2). Non-appcompat style:

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">
    <LinearLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <FrameLayout
        android:id="@+id/templet_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>
Copy the code

# # # the Toolbar template

 <RelativeLayout
        style="@style/base_toolbar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:orientation="horizontal"
        >

        <TextView
            android:id="@+id/tv_left"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:background="@android:color/transparent"
            android:gravity="center"
            />

        <ImageButton
            android:id="@+id/ib_left"
            android:layout_width="48dp"
            android:layout_height="match_parent"
            android:layout_gravity="left"
            android:background="@android:color/transparent"
            android:gravity="center"
            android:src="@drawable/back"
            android:text="Text" on the left
            />

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:layout_gravity="center"
            android:gravity="center"
            />


        <TextView
            android:id="@+id/tv_right"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:background="@null"
            android:gravity="center"
            />

        <ImageButton
            android:id="@+id/ib_right"
            android:layout_width="48dp"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:background="@android:color/transparent"
            android:gravity="center"
            android:visibility="gone"
            />
    </RelativeLayout>
Copy the code

Design idea: 1. The Toolbar must use the Appcompat package, and the plain Acitivity will fail. Use a LinearLayout to add a RelativeLayout. 3 Toolbar. The main content uses FrameLayout, which can be extended to encapsulate loadingView, etc.

##(3).ToolbarHelper: Post only part of the code

Public abstract class ToolbarHelper {/** * set sliding Flag * @param viewId * @param Flag * @return
     */
    public abstract boolean setScrollFlag(@IdRes int viewId, @AppBarLayout.LayoutParams.ScrollFlags int flag); /** * Get View @param viewId @param <V> * @ from AppBarLayoutreturn*/ public abstract <V extends View> V findAppBarView(@IdRes int viewId); /** * Get AppBarLayout * @return*/ public abstract View getAppBarLayout(); /** * get Toolbar * @return
     */
    public abstract Toolbar getToolbar();
}
Copy the code

###

/** * @author jlanglang 2017/2/22 16:58 * @version 2.0 * @change */ baseToolBarPerimpl extends ToolbarLayout {// Int mToolbarLayout; Toolbar mToolbar; // through the UIView interface. UIView mUIView; // View mRootView; AppBarLayout mAppBarLayout; private boolean isMaterialDesign; // Emulate the ViewHolder mechanism. Private SparseArray<View> mViews; public BaseToolBarHelperImpl(@NonNull UIView uiView, View rootView, int toolbarLayout) { mUIView = uiView; mRootView = rootView; mToolbarLayout = toolbarLayout; mViews = new SparseArray<>(); // Initialize AppBarLayout mAppBarLayout = (AppBarLayout) mRootView.findViewById(R.i.ap_bar); mAppBarLayout.removeAllViews(); View inflate = LayOutInflater.from (muiView.getContext ()).inflate(mToolbarLayout, mAppBarLayout,true);
        mToolbar = (Toolbar) inflate.findViewById(R.id.tl_costom);
        if(mToolbar ! = null) {/ / incoming toolbarLayout contained in the Toolbar, set. MUIView. SetSupportActionBar (mToolbar); } // Give subclasses to initialize the Toolbar initToolbar(); } /* * initToolbar */ public void initToolbar(); /** * Get the control from AppBarLayout ** @param viewId * @param <V> * @return
     */
    @Nullable
    @Override
    public <V extends View> V findAppBarView(@IdRes int viewId) {
        View view = mViews.get(viewId);
        if(view == null && mAppBarLayout ! = null) { view = mAppBarLayout.findViewById(viewId); mViews.put(viewId, view); }return(V) view; } /** * set the sliding effect of the control ** @param viewId control resource ID * @param flag sliding flag * @return*/ @override public Boolean Whether the setting was successfulsetScrollFlag(@IdRes int viewId, @AppBarLayout.LayoutParams.ScrollFlags int flag) {
        View view = findAppBarView(viewId);
        if(view ! = null) { try { AppBarLayout.LayoutParams layoutParams = (AppBarLayout.LayoutParams) view.getLayoutParams(); layoutParams.setScrollFlags(flag); } catch (ClassCastException e) { e.printStackTrace();return false;
            } catch (NullPointerException e) {
                e.printStackTrace();
                return false; }}else {
            return false;
        }
        return true;
    }
    @Nullable
    @Override
    public Toolbar getToolbar() {
        return mToolbar;
    }

Copy the code

##BaseAcitivity

package com.baozi.mvpdemo.base; /** * @author jlanglang 2016/1/5 9:42 */ public abstract class BaseActivity<T extends BasePresenter> extends AppCompatActivity implements BaseActivityView { protected T mPresenter; private SparseArray<View> mViews; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mViews = new SparseArray<>(); // Create presenter mPresenter = initPresenter(); // Bind Activity mPresenter. OnAttch (this); // Create ContentView View = initView(LayoutInflater. From (this), savedInstanceState); super.setContentView(view); // Initialize presbyter.oncreate (); // Delay loading data. Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                mPresenter.loadData();
                return false; }}); } @Override public voidsetContentView(@LayoutRes int layoutResID) {

    }

    @Override
    public void setContentView(View view) {

    }

    @Override
    public void setContentView(View View, viewGroup.layoutParams params) {return
     */
    @Override
    public <V extends View> V findView(@IdRes int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = super.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (V) view;
    }

    @Override
    public View findViewById(@IdRes int id) {
        returnfindView(id); } /** * It is recommended not to include toolbar ** @param inflater * @param savedInstanceState * @return*/ @NonNull protected abstract View initView(@NonNull LayoutInflater inflater, Bundle savedInstanceState); /** * Subclasses implement Presenter and must inherit BasePrensenter ** @return
     */
    protected abstract T initPresenter();

}
Copy the code

### Provide template Activity:

/** * Sets the default layout, several default Toolbar templates, implements ToolbarView, */ public abstract class TempletActivity<T extends TempletPresenter> extends BaseActivity<T> implements ToolbarView { private ToolbarHelper mToolbarHelper; private View rootView; @NonNull @Override protected View initView(@NonNull LayoutInflater inflater, Bundle savedInstanceState) { ActionBar supportActionBar = getSupportActionBar();if(supportActionBar ! = null) { throw new IllegalStateException("pleace exends BaseActivity,TempletActivity theme must Noactionbar"); } rootView = inflater.inflate(R.layout.activity_templet, null); // Create toolbar mToolbarHelper = getToolbarHelper(); //ContentView FrameLayout contentGroup = (FrameLayout) rootView.findViewById(R.id.treplet_content); ContentView = initContentView(inflater, contentGroup, savedInstanceState); contentGroup.removeAllViews(); contentGroup.addView(contentView); / / to Persenter extension mPresenter. WapperContentView (contentGroup);returnrootView; }} @nonnull protected Abstract View initContentView(LayoutInflater inflater, @nullable ViewGroup container, Bundle savedInstanceState); /** * Default base_toolbar * If you don't need the toolbar, overwrite it and return 0. Or minus 1 times times the dot signreturn
     */
    @Override
    public int initToolbarLayout() {
        returnToolbarHelper.TOOLBAR_TEMPLET_DEFUATL; } /** * This method is used to initialize the menu, where the menu parameter is the menu instance to be displayed. returntrueThen the menu is displayed.falseDo not display; */ @override public Boolean onCreateOptionsMenu(Menu Menu) {if(! isMaterialDesign() || getToolbarHelper() == null) {return false;
        }
        returnsuper.onCreateOptionsMenu(menu); } /** * called after onCreateOptionsMenu execution, before the menu is displayed; Is called before the menu is displayed, if it has already been created. Again, the * returnstrueThen the menu is displayed.falseDo not display; */ @override public Boolean onPrepareOptionsMenu(Menu Menu) {returnsuper.onPrepareOptionsMenu(menu); } /** * display menu icon ** @param view * @param menu * @return
     */
    @Override
    protected boolean onPrepareOptionsPanel(View view, Menu menu) {
        if(menu ! = null) {if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
                try {
                    Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                    m.setAccessible(true);
                    m.invoke(menu, true);
                } catch (Exception e) {
                    Log.e(getClass().getSimpleName(), "onMenuOpened... unable to set icons for overflow menu", e); }}}returnsuper.onPrepareOptionsPanel(view, menu); } /** * is called each time the menu is closed. */ @override public void onOptionsMenuClosed(menu menu) {Override public void onOptionsMenuClosed(menu menu) { super.onOptionsMenuClosed(menu); } /** * is called when a menu item is clicked, which is the menu item's listening method. */ @override public Boolean onOptionsItemSelected(MenuItem item) {return super.onOptionsItemSelected(item);
    }


    @Override
    public TempletActivity getActivity() {
        returnthis; ** @param isMaterialDesign */ @override public void MaterialDesignsetMaterialDesignEnabled(boolean isMaterialDesign) {
        getToolbarHelper().setMaterialDesignEnabled(isMaterialDesign);
    }

    @Override
    public boolean isMaterialDesign() {
        return false; } /** * Returns null. ** @ if the subject is not NoActionBar or initToolbar() returns 0returnMToolbar may be null. */ public ToolbargetToolbar() {
        returngetToolbarHelper().getToolbar(); } / * * * @return
     */
    @Override
    public ToolbarHelper getToolbarHelper() {
        if (mToolbarHelper == null) {
            mToolbarHelper = ToolbarHelper.Create(this, rootView, initToolbarLayout());
        }
        return mToolbarHelper;
    }

    @Override
    protected abstract T initPresenter();
}

Copy the code

###

public class MainAcitivity extends TempletActivity<TempletPresenter>  {
    @NonNull
    @Override
    protected View initContentView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        getToolbarHelper().setTitle("Home page");
        getToolbarHelper().setRightText("213", null);
        returninflater.inflate(R.layout.activity_main, null); Override protected TempletPresenter @override protected TempletPresenterinitPresenter() {// Need inheritancereturn new TempletPresenter<MainAcitivityContract.View>() {
            @Override
            public void onCreate() {// set the sliding effect mView.getToolBarHelper ().setScrollFlag(r.id.tl_costom, AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL| AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); } @Override public voidloadData() {}}; } // Override this method and set toolbarLayout@override public intinitToolbarLayout() {
        returnToolbarHelper.TOOLBAR_TEMPLET_DEFUATL; }}Copy the code

##(4).Appcompat style essentials:

1. If custom page, or the style of the template does not meet your requirements, can be directly inherit BaseActivity BaseFragment initView (@ NonNull LayoutInflater inflater, Bundle savedInstanceState); This method is equivalent to setContentView(),onCreateView(); Or read on, surprise.

2. Due to BaseActivity BaseFragment inherit UIVIew. The View is initialized with the initView() method so switching between the two can be very minimal.

3.TempletActivity implements ToolbarHelper classes and implements toolbarView. UIView. A TempletActivity can be operated by a View that inherits toolbarView. UIView.

4.BaseActivity and BaseFragment belong to the base class and do not need to be related to toolbars. There is no need for ToolbarHelper

5. By rewriting initToolbarLayout can set different style of the Toolbar (), if the style to meet the requirements, can be directly inherit BaseActivity, BaseFragment from definition

6. Obtain mApplayout using ToolbarHelper to add and delete child views. And set properties.

7. The child controls in mApplayout can be obtained using findAppBarView(ID) in ToolbarHelper.

8. You can set the sliding effect of the mApplayout neutron control using setScrollFlag(ID,flag) in ToolbarHelper. You can customize the ToolbarLayout, but the Toolbar ID must be named TL_costom. You have to do something manually, however, by retrieving the Toolbar with findAppBarView(ID) and setSupportActionBar() ##(5). Take TabLayout Toolbar

2. The Toolbar with nothing

3. Customized some VIew toolbars

4. The collapsed Toolbar can be pushed up by sliding

Disadvantages: Some Settings for AppbarLayout can only be set in code.

# 2. Get rid of butterknife

When practicing componentization, I found that butterKnife was not easy to use and the View could not be found in moudle. Later, I read git’s instructions and changed R to R2. I found that it was a bit painful and not very good, so I simply abandoned it.

Finally, findviewbyId() was rewritten to reduce coercion through generics. You don’t have to force it every time. But have to know the corresponding control ID is what type, this is impossible not to know it.

Part code:

public abstract class BaseActivity<T extends BasePresenter> extends AppCompatActivity implements BaseActivityView { private SparseArray<View> mViews; * Get control via viewId * * @param viewId resource ID * @return
     */
    @Override
    public <V extends View> V findView(@IdRes int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = super.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (V) view;
    }

    @Override
    public View findViewById(@IdRes int id) {
        return findView(id);
    }
Copy the code

Write findViewById yourself. Tool generation is also possible.

#3. Common style specific implementation code will not be posted, this article is very long, ha ha. Interested in github directly look at the code well.

#4. The Fragment Toolbar encapsulation is implemented in much the same way as an Activity, because I’ve always envisioned switching between the two with very little code change. I won’t post it here (I haven’t written it yet). If you look at my series of articles, you will see that the original packaging structure is quite different from today’s. Why don’t you update the old one and I think it’s a record of growth. Ha ha

# add githubdemo address and update mvpDemo from time to time


Your love and reply is my biggest motivation – –