From 280e0fc4b4de707e70a783b9ea7d26e96cdc4399 Mon Sep 17 00:00:00 2001 From: sang84020325 <879689064@qq.com> Date: Sun, 14 May 2017 18:59:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Basemodule/Basemodule.iml | 10 +- Basemodule/build.gradle | 1 - .../basemoudle/base/BaseListActivity.java | 4 +- .../basemoudle/base/BaseListFragment.java | 5 +- .../masterialspinner/MaterialSpinner.java | 527 ----- .../MaterialSpinnerAdapter.java | 53 - .../MaterialSpinnerAdapterWrapper.java | 59 - .../MaterialSpinnerBaseAdapter.java | 99 - .../view/masterialspinner/Utils.java | 91 - .../baseadapter/BaseItemDraggableAdapter.java | 257 +++ .../BaseMultiItemQuickAdapter.java | 66 + .../weight/baseadapter/BaseQuickAdapter.java | 1891 +++++++++++++++++ .../baseadapter/BaseSectionQuickAdapter.java | 65 + .../weight/baseadapter/BaseViewHolder.java | 599 ++++++ .../animation/AlphaInAnimation.java | 28 + .../baseadapter/animation/BaseAnimation.java | 13 + .../animation/ScaleInAnimation.java | 30 + .../animation/SlideInBottomAnimation.java | 21 + .../animation/SlideInLeftAnimation.java | 20 + .../animation/SlideInRightAnimation.java | 20 + .../callback/ItemDragAndSwipeCallback.java | 197 ++ .../entity/AbstractExpandableItem.java | 80 + .../baseadapter/entity/IExpandable.java | 19 + .../baseadapter/entity/MultiItemEntity.java | 10 + .../baseadapter/entity/SectionEntity.java | 22 + .../listener/OnItemChildClickListener.java | 39 + .../OnItemChildLongClickListener.java | 37 + .../listener/OnItemClickListener.java | 39 + .../listener/OnItemDragListener.java | 13 + .../listener/OnItemLongClickListener.java | 36 + .../listener/OnItemSwipeListener.java | 39 + .../listener/SimpleClickListener.java | 302 +++ .../baseadapter/loadmore/LoadMoreView.java | 117 + .../loadmore/SimpleLoadMoreView.java | 27 + .../baseadapter/util/MultiTypeDelegate.java | 90 + .../baseadapter/util/TouchEventUtil.java | 29 + .../main/res/layout/quick_view_load_more.xml | 60 + Basemodule/src/main/res/values/attrs.xml | 35 - Basemodule/src/main/res/values/dimens.xml | 13 +- Basemodule/src/main/res/values/ids.xml | 5 + Basemodule/src/main/res/values/strings.xml | 3 +- app/app.iml | 46 + app/build.gradle | 3 + app/src/main/AndroidManifest.xml | 5 + .../com/basemoudle/sample/MainActivity.java | 46 +- .../sample/activity/MVCActivity.java | 32 + .../sample/activity/MVPActivity.java | 61 + .../java/com/basemoudle/sample/api/Api.java | 185 ++ .../basemoudle/sample/api/ApiConstants.java | 64 + .../com/basemoudle/sample/api/ApiService.java | 18 + .../com/basemoudle/sample/api/HostType.java | 38 + .../basemoudle/sample/app/AppApplication.java | 18 + .../java/com/basemoudle/sample/bean/User.java | 8 + .../sample/contract/MVPContract.java | 30 + .../com/basemoudle/sample/model/MVPModel.java | 20 + .../sample/persenter/MVPPersenter.java | 27 + app/src/main/res/layout/activity_main.xml | 21 +- app/src/main/res/layout/activity_mvp.xml | 12 + 58 files changed, 4812 insertions(+), 893 deletions(-) delete mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinner.java delete mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerAdapter.java delete mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerAdapterWrapper.java delete mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerBaseAdapter.java delete mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/Utils.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseItemDraggableAdapter.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseMultiItemQuickAdapter.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseQuickAdapter.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseSectionQuickAdapter.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseViewHolder.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/AlphaInAnimation.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/BaseAnimation.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/ScaleInAnimation.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInBottomAnimation.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInLeftAnimation.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInRightAnimation.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/callback/ItemDragAndSwipeCallback.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/AbstractExpandableItem.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/IExpandable.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/MultiItemEntity.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/SectionEntity.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemChildClickListener.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemChildLongClickListener.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemClickListener.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemDragListener.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemLongClickListener.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemSwipeListener.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/SimpleClickListener.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/loadmore/LoadMoreView.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/loadmore/SimpleLoadMoreView.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/util/MultiTypeDelegate.java create mode 100644 Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/util/TouchEventUtil.java create mode 100644 Basemodule/src/main/res/layout/quick_view_load_more.xml create mode 100644 app/src/main/java/com/basemoudle/sample/activity/MVCActivity.java create mode 100644 app/src/main/java/com/basemoudle/sample/activity/MVPActivity.java create mode 100644 app/src/main/java/com/basemoudle/sample/api/Api.java create mode 100644 app/src/main/java/com/basemoudle/sample/api/ApiConstants.java create mode 100644 app/src/main/java/com/basemoudle/sample/api/ApiService.java create mode 100644 app/src/main/java/com/basemoudle/sample/api/HostType.java create mode 100644 app/src/main/java/com/basemoudle/sample/app/AppApplication.java create mode 100644 app/src/main/java/com/basemoudle/sample/bean/User.java create mode 100644 app/src/main/java/com/basemoudle/sample/contract/MVPContract.java create mode 100644 app/src/main/java/com/basemoudle/sample/model/MVPModel.java create mode 100644 app/src/main/java/com/basemoudle/sample/persenter/MVPPersenter.java create mode 100644 app/src/main/res/layout/activity_mvp.xml diff --git a/Basemodule/Basemodule.iml b/Basemodule/Basemodule.iml index 385c075..8a97c5d 100644 --- a/Basemodule/Basemodule.iml +++ b/Basemodule/Basemodule.iml @@ -35,7 +35,6 @@ - @@ -43,6 +42,7 @@ + @@ -115,23 +115,23 @@ - + - + - + + - diff --git a/Basemodule/build.gradle b/Basemodule/build.gradle index 4340da2..b6e30d4 100644 --- a/Basemodule/build.gradle +++ b/Basemodule/build.gradle @@ -28,7 +28,6 @@ dependencies { compile 'com.android.support:appcompat-v7:24.+' testCompile 'junit:junit:4.12' compile 'com.android.support:recyclerview-v7:24.+' - compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.+' compile 'me.yokeyword:fragmentation:0.10.0' //retrofit和rxjava compile 'com.squareup.retrofit2:retrofit:2.0.0' diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/base/BaseListActivity.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/base/BaseListActivity.java index 5a1ddfd..5764891 100644 --- a/Basemodule/src/main/java/com/xusangbo/basemoudle/base/BaseListActivity.java +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/base/BaseListActivity.java @@ -5,9 +5,9 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; -import com.chad.library.adapter.base.BaseQuickAdapter; -import com.chad.library.adapter.base.BaseViewHolder; import com.xusangbo.basemodule.R; +import com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter; +import com.xusangbo.basemoudle.weight.baseadapter.BaseViewHolder; import java.util.ArrayList; import java.util.List; diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/base/BaseListFragment.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/base/BaseListFragment.java index 275342b..fc33623 100644 --- a/Basemodule/src/main/java/com/xusangbo/basemoudle/base/BaseListFragment.java +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/base/BaseListFragment.java @@ -5,10 +5,9 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; -import android.view.View; -import com.chad.library.adapter.base.BaseQuickAdapter; -import com.chad.library.adapter.base.BaseViewHolder; import com.xusangbo.basemodule.R; +import com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter; +import com.xusangbo.basemoudle.weight.baseadapter.BaseViewHolder; import java.util.ArrayList; import java.util.List; diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinner.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinner.java deleted file mode 100644 index 0f687b9..0000000 --- a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinner.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (C) 2016 Jared Rummler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.xusangbo.basemoudle.view.masterialspinner; - -import android.animation.ObjectAnimator; -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.StateListDrawable; -import android.os.Build; -import android.os.Bundle; -import android.os.Parcelable; -import android.support.annotation.ColorInt; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.AttributeSet; -import android.util.Log; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.PopupWindow; -import android.widget.TextView; - -import com.xusangbo.basemodule.R; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; - -/** - * A spinner that shows a {@link PopupWindow} under the view when clicked. - */ -public class MaterialSpinner extends TextView { - - private OnNothingSelectedListener onNothingSelectedListener; - private OnItemSelectedListener onItemSelectedListener; - private MaterialSpinnerBaseAdapter adapter; - private PopupWindow popupWindow; - private ListView listView; - private Drawable arrowDrawable; - private boolean hideArrow; - private boolean nothingSelected; - private int popupWindowMaxHeight; - private int popupWindowHeight; - private int selectedIndex; - private int backgroundColor; - private int arrowColor; - private int arrowColorDisabled; - private int textColor; - private int numberOfItems; - - public MaterialSpinner(Context context) { - super(context); - init(context, null); - } - - public MaterialSpinner(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs); - } - - public MaterialSpinner(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs); - } - - private void init(Context context, AttributeSet attrs) { - TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MaterialSpinner); - int defaultColor = getTextColors().getDefaultColor(); - boolean rtl = Utils.isRtl(context); - - try { - backgroundColor = ta.getColor(R.styleable.MaterialSpinner_ms_background_color, Color.WHITE); - textColor = ta.getColor(R.styleable.MaterialSpinner_ms_text_color, defaultColor); - arrowColor = ta.getColor(R.styleable.MaterialSpinner_ms_arrow_tint, textColor); - hideArrow = ta.getBoolean(R.styleable.MaterialSpinner_ms_hide_arrow, false); - popupWindowMaxHeight = ta.getDimensionPixelSize(R.styleable.MaterialSpinner_ms_dropdown_max_height, 0); - popupWindowHeight = ta.getLayoutDimension(R.styleable.MaterialSpinner_ms_dropdown_height, - WindowManager.LayoutParams.WRAP_CONTENT); - arrowColorDisabled = Utils.lighter(arrowColor, 0.8f); - } finally { - ta.recycle(); - } - - Resources resources = getResources(); - int left, right, bottom, top; - left = right = bottom = top = resources.getDimensionPixelSize(R.dimen.ms__padding_top); - if (rtl) { - right = resources.getDimensionPixelSize(R.dimen.ms__padding_left); - } else { - left = resources.getDimensionPixelSize(R.dimen.ms__padding_left); - } - - setGravity(Gravity.CENTER_VERTICAL | Gravity.START); - setClickable(true); - setPadding(left, top, right, bottom); - setBackgroundResource(R.drawable.ms__selector); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && rtl) { - setLayoutDirection(View.LAYOUT_DIRECTION_RTL); - setTextDirection(View.TEXT_DIRECTION_RTL); - } - - if (!hideArrow) { - arrowDrawable = Utils.getDrawable(context, R.drawable.ms__arrow).mutate(); - arrowDrawable.setColorFilter(arrowColor, PorterDuff.Mode.SRC_IN); - if (rtl) { - setCompoundDrawablesWithIntrinsicBounds(arrowDrawable, null, null, null); - } else { - setCompoundDrawablesWithIntrinsicBounds(null, null, arrowDrawable, null); - } - } - - listView = new ListView(context); - listView.setId(getId()); - listView.setDivider(null); - listView.setItemsCanFocus(true); - listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - - @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - if (position >= selectedIndex && position < adapter.getCount()) { - position++; - } - selectedIndex = position; - nothingSelected = false; - Object item = adapter.get(position); - adapter.notifyItemSelected(position); - setText(item.toString()); - collapse(); - if (onItemSelectedListener != null) { - //noinspection unchecked - onItemSelectedListener.onItemSelected(MaterialSpinner.this, position, id, item); - } - } - }); - - popupWindow = new PopupWindow(context); - popupWindow.setContentView(listView); - popupWindow.setOutsideTouchable(true); - popupWindow.setFocusable(true); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - popupWindow.setElevation(16); - popupWindow.setBackgroundDrawable(Utils.getDrawable(context, R.drawable.ms__drawable)); - } else { - popupWindow.setBackgroundDrawable(Utils.getDrawable(context, R.drawable.ms__drop_down_shadow)); - } - - if (backgroundColor != Color.WHITE) { // default color is white - setBackgroundColor(backgroundColor); - } - if (textColor != defaultColor) { - setTextColor(textColor); - } - - popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { - - @Override public void onDismiss() { - if (nothingSelected && onNothingSelectedListener != null) { - onNothingSelectedListener.onNothingSelected(MaterialSpinner.this); - } - if (!hideArrow) { - animateArrow(false); - } - } - }); - } - - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - popupWindow.setWidth(MeasureSpec.getSize(widthMeasureSpec)); - popupWindow.setHeight(calculatePopupWindowHeight()); - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - - @Override public boolean onTouchEvent(@NonNull MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - if (isEnabled() && isClickable()) { - if (!popupWindow.isShowing()) { - expand(); - } else { - collapse(); - } - } - } - return super.onTouchEvent(event); - } - - @Override public void setBackgroundColor(int color) { - backgroundColor = color; - Drawable background = getBackground(); - if (background instanceof StateListDrawable) { // pre-L - try { - Method getStateDrawable = StateListDrawable.class.getDeclaredMethod("getStateDrawable", int.class); - if (!getStateDrawable.isAccessible()) getStateDrawable.setAccessible(true); - int[] colors = {Utils.darker(color, 0.85f), color}; - for (int i = 0; i < colors.length; i++) { - ColorDrawable drawable = (ColorDrawable) getStateDrawable.invoke(background, i); - drawable.setColor(colors[i]); - } - } catch (Exception e) { - Log.e("MaterialSpinner", "Error setting background color", e); - } - } else if (background != null) { // 21+ (RippleDrawable) - background.setColorFilter(color, PorterDuff.Mode.SRC_IN); - } - popupWindow.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_IN); - } - - @Override public void setTextColor(int color) { - textColor = color; - super.setTextColor(color); - } - - @Override public Parcelable onSaveInstanceState() { - Bundle bundle = new Bundle(); - bundle.putParcelable("state", super.onSaveInstanceState()); - bundle.putInt("selected_index", selectedIndex); - if (popupWindow != null) { - bundle.putBoolean("is_popup_showing", popupWindow.isShowing()); - collapse(); - } else { - bundle.putBoolean("is_popup_showing", false); - } - return bundle; - } - - @Override public void onRestoreInstanceState(Parcelable savedState) { - if (savedState instanceof Bundle) { - Bundle bundle = (Bundle) savedState; - selectedIndex = bundle.getInt("selected_index"); - if (adapter != null) { - setText(adapter.get(selectedIndex).toString()); - adapter.notifyItemSelected(selectedIndex); - } - if (bundle.getBoolean("is_popup_showing")) { - if (popupWindow != null) { - // Post the show request into the looper to avoid bad token exception - post(new Runnable() { - - @Override public void run() { - expand(); - } - }); - } - } - savedState = bundle.getParcelable("state"); - } - super.onRestoreInstanceState(savedState); - } - - @Override public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - if (arrowDrawable != null) { - arrowDrawable.setColorFilter(enabled ? arrowColor : arrowColorDisabled, PorterDuff.Mode.SRC_IN); - } - } - - /** - * @return the selected item position - */ - public int getSelectedIndex() { - return selectedIndex; - } - - /** - * Set the default spinner item using its index - * - * @param position - * the item's position - */ - public void setSelectedIndex(int position) { - if (adapter != null) { - if (position >= 0 && position <= adapter.getCount()) { - adapter.notifyItemSelected(position); - selectedIndex = position; - setText(adapter.get(position).toString()); - } else { - throw new IllegalArgumentException("Position must be lower than adapter count!"); - } - } - } - - /** - * Register a callback to be invoked when an item in the dropdown is selected. - * - * @param onItemSelectedListener - * The callback that will run - */ - public void setOnItemSelectedListener(@Nullable OnItemSelectedListener onItemSelectedListener) { - this.onItemSelectedListener = onItemSelectedListener; - } - - /** - * Register a callback to be invoked when the {@link PopupWindow} is shown but the user didn't select an item. - * - * @param onNothingSelectedListener - * the callback that will run - */ - public void setOnNothingSelectedListener(@Nullable OnNothingSelectedListener onNothingSelectedListener) { - this.onNothingSelectedListener = onNothingSelectedListener; - } - - /** - * Set the dropdown items - * - * @param items - * A list of items - * @param - * The item type - */ - public void setItems(@NonNull List items) { - numberOfItems = items.size(); - adapter = new MaterialSpinnerAdapter<>(getContext(), items).setTextColor(textColor); - setAdapterInternal(adapter); - } - - /** - * Set the dropdown items - * - * @param items - * A list of items - * @param - * The item type - */ - public void setItems(@NonNull T... items) { - setItems(Arrays.asList(items)); - } - - /** - * Get the list of items in the adapter - * - * @param - * The item type - * @return A list of items or {@code null} if no items are set. - */ - public List getItems() { - if (adapter == null) { - return null; - } - //noinspection unchecked - return adapter.getItems(); - } - - /** - * Set a custom adapter for the dropdown items - * - * @param adapter - * The list adapter - */ - public void setAdapter(@NonNull ListAdapter adapter) { - this.adapter = new MaterialSpinnerAdapterWrapper(getContext(), adapter); - setAdapterInternal(this.adapter); - } - - public void setAdapter(MaterialSpinnerAdapter adapter) { - this.adapter = adapter; - setAdapterInternal(adapter); - } - - private void setAdapterInternal(@NonNull MaterialSpinnerBaseAdapter adapter) { - listView.setAdapter(adapter); - if (selectedIndex >= numberOfItems) { - selectedIndex = 0; - } - setText(adapter.get(selectedIndex).toString()); - } - - /** - * Show the dropdown menu - */ - public void expand() { - if (!hideArrow) { - animateArrow(true); - } - nothingSelected = true; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - popupWindow.setOverlapAnchor(false); - popupWindow.showAsDropDown(this); - } else { - int[] location = new int[2]; - getLocationOnScreen(location); - int x = location[0]; - int y = getHeight() + location[1]; - popupWindow.showAtLocation(this, Gravity.TOP | Gravity.START, x, y); - } - } - - /** - * Closes the dropdown menu - */ - public void collapse() { - if (!hideArrow) { - animateArrow(false); - } - popupWindow.dismiss(); - } - - /** - * Set the tint color for the dropdown arrow - * - * @param color - * the color value - */ - public void setArrowColor(@ColorInt int color) { - arrowColor = color; - arrowColorDisabled = Utils.lighter(arrowColor, 0.8f); - if (arrowDrawable != null) { - arrowDrawable.setColorFilter(arrowColor, PorterDuff.Mode.SRC_IN); - } - } - - private void animateArrow(boolean shouldRotateUp) { - int start = shouldRotateUp ? 0 : 10000; - int end = shouldRotateUp ? 10000 : 0; - ObjectAnimator animator = ObjectAnimator.ofInt(arrowDrawable, "level", start, end); - animator.start(); - } - - /** - * Set the maximum height of the dropdown menu. - * - * @param height - * the height in pixels - */ - public void setDropdownMaxHeight(int height) { - popupWindowMaxHeight = height; - popupWindow.setHeight(calculatePopupWindowHeight()); - } - - /** - * Set the height of the dropdown menu - * - * @param height - * the height in pixels - */ - public void setDropdownHeight(int height) { - popupWindowHeight = height; - popupWindow.setHeight(calculatePopupWindowHeight()); - } - - private int calculatePopupWindowHeight() { - if (adapter == null) { - return WindowManager.LayoutParams.WRAP_CONTENT; - } - float listViewHeight = adapter.getCount() * getResources().getDimension(R.dimen.ms__item_height); - if (popupWindowMaxHeight > 0 && listViewHeight > popupWindowMaxHeight) { - return popupWindowMaxHeight; - } else if (popupWindowHeight != WindowManager.LayoutParams.MATCH_PARENT - && popupWindowHeight != WindowManager.LayoutParams.WRAP_CONTENT - && popupWindowHeight <= listViewHeight) { - return popupWindowHeight; - } - return WindowManager.LayoutParams.WRAP_CONTENT; - } - - /** - * Get the {@link PopupWindow}. - * - * @return The {@link PopupWindow} that is displayed when the view has been clicked. - */ - public PopupWindow getPopupWindow() { - return popupWindow; - } - - /** - * Interface definition for a callback to be invoked when an item in this view has been selected. - * - * @param - * Adapter item type - */ - public interface OnItemSelectedListener { - - /** - *

Callback method to be invoked when an item in this view has been selected. This callback is invoked only when - * the newly selected position is different from the previously selected position or if there was no selected - * item.

- * - * @param view - * The {@link MaterialSpinner} view - * @param position - * The position of the view in the adapter - * @param id - * The row id of the item that is selected - * @param item - * The selected item - */ - void onItemSelected(MaterialSpinner view, int position, long id, T item); - - } - - /** - * Interface definition for a callback to be invoked when the dropdown is dismissed and no item was selected. - */ - public interface OnNothingSelectedListener { - - /** - * Callback method to be invoked when the {@link PopupWindow} is dismissed and no item was selected. - * - * @param spinner - * the {@link MaterialSpinner} - */ - void onNothingSelected(MaterialSpinner spinner); - } - -} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerAdapter.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerAdapter.java deleted file mode 100644 index f297746..0000000 --- a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerAdapter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2016 Jared Rummler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.xusangbo.basemoudle.view.masterialspinner; - -import android.content.Context; - -import java.util.List; - -public class MaterialSpinnerAdapter extends MaterialSpinnerBaseAdapter { - - private final List items; - - public MaterialSpinnerAdapter(Context context, List items) { - super(context); - this.items = items; - } - - @Override public int getCount() { - return items.size() - 1; - } - - @Override public T getItem(int position) { - if (position >= getSelectedIndex()) { - return items.get(position + 1); - } else { - return items.get(position); - } - } - - @Override public T get(int position) { - return items.get(position); - } - - @Override public List getItems() { - return items; - } - -} \ No newline at end of file diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerAdapterWrapper.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerAdapterWrapper.java deleted file mode 100644 index e4cf387..0000000 --- a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerAdapterWrapper.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2016 Jared Rummler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.xusangbo.basemoudle.view.masterialspinner; - -import android.content.Context; -import android.widget.ListAdapter; - -import java.util.ArrayList; -import java.util.List; - -final class MaterialSpinnerAdapterWrapper extends MaterialSpinnerBaseAdapter { - - private final ListAdapter listAdapter; - - public MaterialSpinnerAdapterWrapper(Context context, ListAdapter toWrap) { - super(context); - listAdapter = toWrap; - } - - @Override public int getCount() { - return listAdapter.getCount() - 1; - } - - @Override public Object getItem(int position) { - if (position >= getSelectedIndex()) { - return listAdapter.getItem(position + 1); - } else { - return listAdapter.getItem(position); - } - } - - @Override public Object get(int position) { - return listAdapter.getItem(position); - } - - @Override public List getItems() { - List items = new ArrayList<>(); - for (int i = 0; i < getCount(); i++) { - items.add(getItem(i)); - } - return items; - } - -} \ No newline at end of file diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerBaseAdapter.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerBaseAdapter.java deleted file mode 100644 index bb6e684..0000000 --- a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/MaterialSpinnerBaseAdapter.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2016 Jared Rummler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.xusangbo.basemoudle.view.masterialspinner; - -import android.content.Context; -import android.content.res.Configuration; -import android.os.Build; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import com.xusangbo.basemodule.R; - -import java.util.List; - -public abstract class MaterialSpinnerBaseAdapter extends BaseAdapter { - - private final Context context; - private int selectedIndex; - private int textColor; - - public MaterialSpinnerBaseAdapter(Context context) { - this.context = context; - } - - @Override public View getView(int position, View convertView, ViewGroup parent) { - final TextView textView; - if (convertView == null) { - LayoutInflater inflater = LayoutInflater.from(context); - convertView = inflater.inflate(R.layout.ms__list_item, parent, false); - textView = (TextView) convertView.findViewById(R.id.tv_tinted_spinner); - textView.setTextColor(textColor); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - Configuration config = context.getResources().getConfiguration(); - if (config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { - textView.setTextDirection(View.TEXT_DIRECTION_RTL); - } - } - convertView.setTag(new ViewHolder(textView)); - } else { - textView = ((ViewHolder) convertView.getTag()).textView; - } - textView.setText(getItem(position).toString()); - return convertView; - } - - public int getSelectedIndex() { - return selectedIndex; - } - - public void notifyItemSelected(int index) { - selectedIndex = index; - } - - @Override public long getItemId(int position) { - return position; - } - - @Override public abstract T getItem(int position); - - @Override public abstract int getCount(); - - public abstract T get(int position); - - public abstract List getItems(); - - public MaterialSpinnerBaseAdapter setTextColor(int textColor) { - this.textColor = textColor; - return this; - } - - private static class ViewHolder { - - private TextView textView; - - private ViewHolder(TextView textView) { - this.textView = textView; - } - - } - -} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/Utils.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/Utils.java deleted file mode 100644 index d5580a2..0000000 --- a/Basemodule/src/main/java/com/xusangbo/basemoudle/view/masterialspinner/Utils.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2016 Jared Rummler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.xusangbo.basemoudle.view.masterialspinner; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.view.View; - -final class Utils { - - /** - * Darkens a color by a given factor. - * - * @param color - * the color to darken - * @param factor - * The factor to darken the color. - * @return darker version of specified color. - */ - static int darker(int color, float factor) { - return Color.argb(Color.alpha(color), Math.max((int) (Color.red(color) * factor), 0), - Math.max((int) (Color.green(color) * factor), 0), - Math.max((int) (Color.blue(color) * factor), 0)); - } - - /** - * Lightens a color by a given factor. - * - * @param color - * The color to lighten - * @param factor - * The factor to lighten the color. 0 will make the color unchanged. 1 will make the - * color white. - * @return lighter version of the specified color. - */ - static int lighter(int color, float factor) { - int red = (int) ((Color.red(color) * (1 - factor) / 255 + factor) * 255); - int green = (int) ((Color.green(color) * (1 - factor) / 255 + factor) * 255); - int blue = (int) ((Color.blue(color) * (1 - factor) / 255 + factor) * 255); - return Color.argb(Color.alpha(color), red, green, blue); - } - - /** - * Check if layout direction is RTL - * - * @param context - * the current context - * @return {@code true} if the layout direction is right-to-left - */ - static boolean isRtl(Context context) { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && - context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - } - - /** - * Return a drawable object associated with a particular resource ID. - * - *

Starting in {@link Build.VERSION_CODES#LOLLIPOP}, the returned drawable will be styled for the - * specified Context's theme.

- * - * @param id - * The desired resource identifier, as generated by the aapt tool. - * This integer encodes the package, type, and resource entry. - * The value 0 is an invalid identifier. - * @return Drawable An object that can be used to draw this resource. - */ - static Drawable getDrawable(Context context, int id) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return context.getDrawable(id); - } - return context.getResources().getDrawable(id); - } - -} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseItemDraggableAdapter.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseItemDraggableAdapter.java new file mode 100644 index 0000000..37d967f --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseItemDraggableAdapter.java @@ -0,0 +1,257 @@ +package com.xusangbo.basemoudle.weight.baseadapter; + +import android.graphics.Canvas; +import android.support.annotation.NonNull; +import android.support.v4.view.MotionEventCompat; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.view.MotionEvent; +import android.view.View; + + +import com.xusangbo.basemodule.R; +import com.xusangbo.basemoudle.weight.baseadapter.callback.ItemDragAndSwipeCallback; +import com.xusangbo.basemoudle.weight.baseadapter.listener.OnItemDragListener; +import com.xusangbo.basemoudle.weight.baseadapter.listener.OnItemSwipeListener; + +import java.util.Collections; +import java.util.List; + +/** + * Created by luoxw on 2016/7/13. + */ +public abstract class BaseItemDraggableAdapter extends BaseQuickAdapter { + + private static final int NO_TOGGLE_VIEW = 0; + protected int mToggleViewId = NO_TOGGLE_VIEW; + protected ItemTouchHelper mItemTouchHelper; + protected boolean itemDragEnabled = false; + protected boolean itemSwipeEnabled = false; + protected OnItemDragListener mOnItemDragListener; + protected OnItemSwipeListener mOnItemSwipeListener; + protected boolean mDragOnLongPress = true; + + protected View.OnTouchListener mOnToggleViewTouchListener; + protected View.OnLongClickListener mOnToggleViewLongClickListener; + + private static final String ERROR_NOT_SAME_ITEMTOUCHHELPER = "Item drag and item swipe should pass the same ItemTouchHelper"; + + + public BaseItemDraggableAdapter(List data) { + super(data); + } + + public BaseItemDraggableAdapter(int layoutResId, List data) { + super(layoutResId, data); + } + + + /** + * To bind different types of holder and solve different the bind events + * + * @param holder + * @param positions + * @see #getDefItemViewType(int) + */ + @Override + public void onBindViewHolder(K holder, int positions) { + super.onBindViewHolder(holder, positions); + int viewType = holder.getItemViewType(); + + if (mItemTouchHelper != null && itemDragEnabled && viewType != LOADING_VIEW && viewType != HEADER_VIEW + && viewType != EMPTY_VIEW && viewType != FOOTER_VIEW) { + if (mToggleViewId != NO_TOGGLE_VIEW) { + View toggleView = ((BaseViewHolder) holder).getView(mToggleViewId); + if (toggleView != null) { + toggleView.setTag(R.id.BaseQuickAdapter_viewholder_support, holder); + if (mDragOnLongPress) { + toggleView.setOnLongClickListener(mOnToggleViewLongClickListener); + } else { + toggleView.setOnTouchListener(mOnToggleViewTouchListener); + } + } + } else { + holder.itemView.setTag(R.id.BaseQuickAdapter_viewholder_support, holder); + holder.itemView.setOnLongClickListener(mOnToggleViewLongClickListener); + } + } + } + + + /** + * Set the toggle view's id which will trigger drag event. + * If the toggle view id is not set, drag event will be triggered when the item is long pressed. + * + * @param toggleViewId the toggle view's id + */ + public void setToggleViewId(int toggleViewId) { + mToggleViewId = toggleViewId; + } + + /** + * Set the drag event should be trigger on long press. + * Work when the toggleViewId has been set. + * + * @param longPress by default is true. + */ + public void setToggleDragOnLongPress(boolean longPress) { + mDragOnLongPress = longPress; + if (mDragOnLongPress) { + mOnToggleViewTouchListener = null; + mOnToggleViewLongClickListener = new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + if (mItemTouchHelper != null && itemDragEnabled) { + mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(R.id.BaseQuickAdapter_viewholder_support)); + } + return true; + } + }; + } else { + mOnToggleViewTouchListener = new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN + && !mDragOnLongPress) { + if (mItemTouchHelper != null && itemDragEnabled) { + mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(R.id.BaseQuickAdapter_viewholder_support)); + } + return true; + } else { + return false; + } + } + }; + mOnToggleViewLongClickListener = null; + } + } + + /** + * Enable drag items. + * Use itemView as the toggleView when long pressed. + * + * @param itemTouchHelper {@link ItemTouchHelper} + */ + public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper) { + enableDragItem(itemTouchHelper, NO_TOGGLE_VIEW, true); + } + + /** + * Enable drag items. Use the specified view as toggle. + * + * @param itemTouchHelper {@link ItemTouchHelper} + * @param toggleViewId The toggle view's id. + * @param dragOnLongPress If true the drag event will be trigger on long press, otherwise on touch down. + */ + public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper, int toggleViewId, boolean dragOnLongPress) { + itemDragEnabled = true; + mItemTouchHelper = itemTouchHelper; + setToggleViewId(toggleViewId); + setToggleDragOnLongPress(dragOnLongPress); + } + + /** + * Disable drag items. + */ + public void disableDragItem() { + itemDragEnabled = false; + mItemTouchHelper = null; + } + + public boolean isItemDraggable() { + return itemDragEnabled; + } + + /** + *

Enable swipe items.

+ * You should attach {@link ItemTouchHelper} which construct with {@link ItemDragAndSwipeCallback} to the Recycler when you enable this. + */ + public void enableSwipeItem() { + itemSwipeEnabled = true; + } + + public void disableSwipeItem() { + itemSwipeEnabled = false; + } + + public boolean isItemSwipeEnable() { + return itemSwipeEnabled; + } + + /** + * @param onItemDragListener Register a callback to be invoked when drag event happen. + */ + public void setOnItemDragListener(OnItemDragListener onItemDragListener) { + mOnItemDragListener = onItemDragListener; + } + + public int getViewHolderPosition(RecyclerView.ViewHolder viewHolder) { + return viewHolder.getAdapterPosition() - getHeaderLayoutCount(); + } + + public void onItemDragStart(RecyclerView.ViewHolder viewHolder) { + if (mOnItemDragListener != null && itemDragEnabled) { + mOnItemDragListener.onItemDragStart(viewHolder, getViewHolderPosition(viewHolder)); + } + } + + public void onItemDragMoving(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { + int from = getViewHolderPosition(source); + int to = getViewHolderPosition(target); + + if (from < to) { + for (int i = from; i < to; i++) { + Collections.swap(mData, i, i + 1); + } + } else { + for (int i = from; i > to; i--) { + Collections.swap(mData, i, i - 1); + } + } + notifyItemMoved(source.getAdapterPosition(), target.getAdapterPosition()); + + if (mOnItemDragListener != null && itemDragEnabled) { + mOnItemDragListener.onItemDragMoving(source, from, target, to); + } + } + + public void onItemDragEnd(RecyclerView.ViewHolder viewHolder) { + if (mOnItemDragListener != null && itemDragEnabled) { + mOnItemDragListener.onItemDragEnd(viewHolder, getViewHolderPosition(viewHolder)); + } + } + + public void setOnItemSwipeListener(OnItemSwipeListener listener) { + mOnItemSwipeListener = listener; + } + + public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder) { + if (mOnItemSwipeListener != null && itemSwipeEnabled) { + mOnItemSwipeListener.onItemSwipeStart(viewHolder, getViewHolderPosition(viewHolder)); + } + } + + public void onItemSwipeClear(RecyclerView.ViewHolder viewHolder) { + if (mOnItemSwipeListener != null && itemSwipeEnabled) { + mOnItemSwipeListener.clearView(viewHolder, getViewHolderPosition(viewHolder)); + } + } + + public void onItemSwiped(RecyclerView.ViewHolder viewHolder) { + if (mOnItemSwipeListener != null && itemSwipeEnabled) { + mOnItemSwipeListener.onItemSwiped(viewHolder, getViewHolderPosition(viewHolder)); + } + + int pos = getViewHolderPosition(viewHolder); + + mData.remove(pos); + notifyItemRemoved(viewHolder.getAdapterPosition()); + } + + public void onItemSwiping(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive) { + if (mOnItemSwipeListener != null && itemSwipeEnabled) { + mOnItemSwipeListener.onItemSwipeMoving(canvas, viewHolder, dX, dY, isCurrentlyActive); + } + } + +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseMultiItemQuickAdapter.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseMultiItemQuickAdapter.java new file mode 100644 index 0000000..37704db --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseMultiItemQuickAdapter.java @@ -0,0 +1,66 @@ +package com.xusangbo.basemoudle.weight.baseadapter; + +import android.support.annotation.LayoutRes; +import android.util.SparseArray; +import android.view.ViewGroup; + + +import com.xusangbo.basemoudle.weight.baseadapter.entity.MultiItemEntity; + +import java.util.List; + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public abstract class BaseMultiItemQuickAdapter extends BaseQuickAdapter { + + /** + * layouts indexed with their types + */ + private SparseArray layouts; + + private static final int DEFAULT_VIEW_TYPE = -0xff; + + /** + * Same as QuickAdapter#QuickAdapter(Context,int) but with + * some initialization data. + * + * @param data A new list is created out of this one to avoid mutable list + */ + public BaseMultiItemQuickAdapter( List data) { + super( data); + } + + @Override + protected int getDefItemViewType(int position) { + Object item = mData.get(position); + if (item instanceof MultiItemEntity) { + return ((MultiItemEntity)item).getItemType(); + } + return DEFAULT_VIEW_TYPE; + } + + protected void setDefaultViewTypeLayout(@LayoutRes int layoutResId) { + addItemType(DEFAULT_VIEW_TYPE, layoutResId); + } + + @Override + protected K onCreateDefViewHolder(ViewGroup parent, int viewType) { + return createBaseViewHolder(parent, getLayoutId(viewType)); + } + + private int getLayoutId(int viewType) { + return layouts.get(viewType); + } + + protected void addItemType(int type, @LayoutRes int layoutResId) { + if (layouts == null) { + layouts = new SparseArray<>(); + } + layouts.put(type, layoutResId); + } + + +} + + diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseQuickAdapter.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseQuickAdapter.java new file mode 100644 index 0000000..156b6c7 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseQuickAdapter.java @@ -0,0 +1,1891 @@ +/* + * Copyright 2013 Joan Zapata + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.xusangbo.basemoudle.weight.baseadapter; + +import android.animation.Animator; +import android.content.Context; +import android.support.annotation.IdRes; +import android.support.annotation.IntDef; +import android.support.annotation.IntRange; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.RecyclerView.LayoutParams; +import android.support.v7.widget.StaggeredGridLayoutManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + + +import com.xusangbo.basemoudle.weight.baseadapter.animation.AlphaInAnimation; +import com.xusangbo.basemoudle.weight.baseadapter.animation.BaseAnimation; +import com.xusangbo.basemoudle.weight.baseadapter.animation.ScaleInAnimation; +import com.xusangbo.basemoudle.weight.baseadapter.animation.SlideInBottomAnimation; +import com.xusangbo.basemoudle.weight.baseadapter.animation.SlideInLeftAnimation; +import com.xusangbo.basemoudle.weight.baseadapter.animation.SlideInRightAnimation; +import com.xusangbo.basemoudle.weight.baseadapter.entity.IExpandable; +import com.xusangbo.basemoudle.weight.baseadapter.loadmore.LoadMoreView; +import com.xusangbo.basemoudle.weight.baseadapter.loadmore.SimpleLoadMoreView; +import com.xusangbo.basemoudle.weight.baseadapter.util.MultiTypeDelegate; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; + + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public abstract class BaseQuickAdapter extends RecyclerView.Adapter { + + //load more + private boolean mNextLoadEnable = false; + private boolean mLoadMoreEnable = false; + private boolean mLoading = false; + private LoadMoreView mLoadMoreView = new SimpleLoadMoreView(); + private RequestLoadMoreListener mRequestLoadMoreListener; + + //Animation + /** + * Use with {@link #openLoadAnimation} + */ + public static final int ALPHAIN = 0x00000001; + /** + * Use with {@link #openLoadAnimation} + */ + public static final int SCALEIN = 0x00000002; + /** + * Use with {@link #openLoadAnimation} + */ + public static final int SLIDEIN_BOTTOM = 0x00000003; + /** + * Use with {@link #openLoadAnimation} + */ + public static final int SLIDEIN_LEFT = 0x00000004; + /** + * Use with {@link #openLoadAnimation} + */ + public static final int SLIDEIN_RIGHT = 0x00000005; + private OnItemClickListener mOnItemClickListener; + private OnItemLongClickListener mOnItemLongClickListener; + private OnItemChildClickListener mOnItemChildClickListener; + private OnItemChildLongClickListener mOnItemChildLongClickListener; + + @IntDef({ALPHAIN, SCALEIN, SLIDEIN_BOTTOM, SLIDEIN_LEFT, SLIDEIN_RIGHT}) + @Retention(RetentionPolicy.SOURCE) + public @interface AnimationType { + } + + private boolean mFirstOnlyEnable = true; + private boolean mOpenAnimationEnable = false; + private Interpolator mInterpolator = new LinearInterpolator(); + private int mDuration = 300; + private int mLastPosition = -1; + + private BaseAnimation mCustomAnimation; + private BaseAnimation mSelectAnimation = new AlphaInAnimation(); + //header footer + private LinearLayout mHeaderLayout; + private LinearLayout mFooterLayout; + //empty + private FrameLayout mEmptyLayout; + private boolean mIsUseEmpty = true; + private boolean mHeadAndEmptyEnable; + private boolean mFootAndEmptyEnable; + + protected static final String TAG = BaseQuickAdapter.class.getSimpleName(); + protected Context mContext; + protected int mLayoutResId; + protected LayoutInflater mLayoutInflater; + protected List mData; + public static final int HEADER_VIEW = 0x00000111; + public static final int LOADING_VIEW = 0x00000222; + public static final int FOOTER_VIEW = 0x00000333; + public static final int EMPTY_VIEW = 0x00000555; + + private RecyclerView mRecyclerView; + + protected RecyclerView getRecyclerView() { + return mRecyclerView; + } + + private void setRecyclerView(RecyclerView recyclerView) { + mRecyclerView = recyclerView; + } + + private void checkNotNull() { + if (getRecyclerView() == null) { + throw new RuntimeException("please bind recyclerView first!"); + } + } + + /** + * same as recyclerView.setAdapter(), and save the instance of recyclerView + */ + public void bindToRecyclerView(RecyclerView recyclerView) { + if (getRecyclerView() != null) { + throw new RuntimeException("Don't bind twice"); + } + setRecyclerView(recyclerView); + getRecyclerView().setAdapter(this); + } + + /** + * @see #setOnLoadMoreListener(RequestLoadMoreListener, RecyclerView) + * @deprecated This method is because it can lead to crash: always call this method while RecyclerView is computing a layout or scrolling. + * Please use {@link #setOnLoadMoreListener(RequestLoadMoreListener, RecyclerView)} + */ + @Deprecated + public void setOnLoadMoreListener(RequestLoadMoreListener requestLoadMoreListener) { + openLoadMore(requestLoadMoreListener); + } + + private void openLoadMore(RequestLoadMoreListener requestLoadMoreListener) { + this.mRequestLoadMoreListener = requestLoadMoreListener; + mNextLoadEnable = true; + mLoadMoreEnable = true; + mLoading = false; + } + + public void setOnLoadMoreListener(RequestLoadMoreListener requestLoadMoreListener, RecyclerView recyclerView) { + openLoadMore(requestLoadMoreListener); + if (getRecyclerView() == null) { + setRecyclerView(recyclerView); + } + } + + /** + * bind recyclerView {@link #bindToRecyclerView(RecyclerView)} before use! + * + * @see #disableLoadMoreIfNotFullPage(RecyclerView) + */ + public void disableLoadMoreIfNotFullPage() { + checkNotNull(); + disableLoadMoreIfNotFullPage(getRecyclerView()); + } + + /** + * check if full page after {@link #setNewData(List)}, if full, it will enable load more again. + * + * @param recyclerView your recyclerView + * @see #setNewData(List) + */ + public void disableLoadMoreIfNotFullPage(RecyclerView recyclerView) { + setEnableLoadMore(false); + if (recyclerView == null) return; + RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); + if (manager == null) return; + if (manager instanceof LinearLayoutManager) { + final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) manager; + recyclerView.postDelayed(new Runnable() { + @Override + public void run() { + if ((linearLayoutManager.findLastCompletelyVisibleItemPosition() + 1) != getItemCount()) { + setEnableLoadMore(true); + } + } + }, 50); + } else if (manager instanceof StaggeredGridLayoutManager) { + final StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) manager; + recyclerView.postDelayed(new Runnable() { + @Override + public void run() { + final int[] positions = new int[staggeredGridLayoutManager.getSpanCount()]; + staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(positions); + int pos = getTheBiggestNumber(positions) + 1; + if (pos != getItemCount()) { + setEnableLoadMore(true); + } + } + }, 50); + } + } + + private int getTheBiggestNumber(int[] numbers) { + int tmp = -1; + if (numbers == null || numbers.length == 0) { + return tmp; + } + for (int num : numbers) { + if (num > tmp) { + tmp = num; + } + } + return tmp; + } + + public void setNotDoAnimationCount(int count) { + mLastPosition = count; + } + + /** + * Set custom load more + * + * @param loadingView + */ + public void setLoadMoreView(LoadMoreView loadingView) { + this.mLoadMoreView = loadingView; + } + + /** + * Load more view count + * + * @return 0 or 1 + */ + public int getLoadMoreViewCount() { + if (mRequestLoadMoreListener == null || !mLoadMoreEnable) { + return 0; + } + if (!mNextLoadEnable && mLoadMoreView.isLoadEndMoreGone()) { + return 0; + } + if (mData.size() == 0) { + return 0; + } + return 1; + } + + /** + * @return Whether the Adapter is actively showing load + * progress. + */ + public boolean isLoading() { + return mLoading; + } + + + /** + * Refresh end, no more data + */ + public void loadMoreEnd() { + loadMoreEnd(false); + } + + /** + * Refresh end, no more data + * + * @param gone if true gone the load more view + */ + public void loadMoreEnd(boolean gone) { + if (getLoadMoreViewCount() == 0) { + return; + } + mLoading = false; + mNextLoadEnable = false; + mLoadMoreView.setLoadMoreEndGone(gone); + if (gone) { + notifyItemRemoved(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount()); + } else { + mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_END); + notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount()); + } + } + + /** + * Refresh complete + */ + public void loadMoreComplete() { + if (getLoadMoreViewCount() == 0) { + return; + } + mLoading = false; + mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT); + notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount()); + } + + /** + * Refresh failed + */ + public void loadMoreFail() { + if (getLoadMoreViewCount() == 0) { + return; + } + mLoading = false; + mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_FAIL); + notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount()); + } + + /** + * Set the enabled state of load more. + * + * @param enable True if load more is enabled, false otherwise. + */ + public void setEnableLoadMore(boolean enable) { + int oldLoadMoreCount = getLoadMoreViewCount(); + mLoadMoreEnable = enable; + int newLoadMoreCount = getLoadMoreViewCount(); + + if (oldLoadMoreCount == 1) { + if (newLoadMoreCount == 0) { + notifyItemRemoved(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount()); + } + } else { + if (newLoadMoreCount == 1) { + mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT); + notifyItemInserted(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount()); + } + } + } + + /** + * Returns the enabled status for load more. + * + * @return True if load more is enabled, false otherwise. + */ + public boolean isLoadMoreEnable() { + return mLoadMoreEnable; + } + + /** + * Sets the duration of the animation. + * + * @param duration The length of the animation, in milliseconds. + */ + public void setDuration(int duration) { + mDuration = duration; + } + + + /** + * Same as QuickAdapter#QuickAdapter(Context,int) but with + * some initialization data. + * + * @param layoutResId The layout resource id of each item. + * @param data A new list is created out of this one to avoid mutable list + */ + public BaseQuickAdapter(@LayoutRes int layoutResId, @Nullable List data) { + this.mData = data == null ? new ArrayList() : data; + if (layoutResId != 0) { + this.mLayoutResId = layoutResId; + } + } + + public BaseQuickAdapter(@Nullable List data) { + this(0, data); + } + + public BaseQuickAdapter(@LayoutRes int layoutResId) { + this(layoutResId, null); + } + + /** + * setting up a new instance to data; + * + * @param data + */ + public void setNewData(@Nullable List data) { + this.mData = data == null ? new ArrayList() : data; + if (mRequestLoadMoreListener != null) { + mNextLoadEnable = true; + mLoadMoreEnable = true; + mLoading = false; + mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT); + } + mLastPosition = -1; + notifyDataSetChanged(); + } + + + /** + * insert a item associated with the specified position of adapter + * + * @param position + * @param item + * @deprecated use {@link #addData(int, Object)} instead + */ + @Deprecated + public void add(@IntRange(from = 0) int position, @NonNull T item) { + addData(position, item); + } + + /** + * add one new data in to certain location + * + * @param position + */ + public void addData(@IntRange(from = 0) int position, @NonNull T data) { + mData.add(position, data); + notifyItemInserted(position + getHeaderLayoutCount()); + compatibilityDataSizeChanged(1); + } + + /** + * add one new data + */ + public void addData(@NonNull T data) { + mData.add(data); + notifyItemInserted(mData.size() + getHeaderLayoutCount()); + compatibilityDataSizeChanged(1); + } + + /** + * remove the item associated with the specified position of adapter + * + * @param position + */ + public void remove(@IntRange(from = 0) int position) { + mData.remove(position); + int internalPosition = position + getHeaderLayoutCount(); + notifyItemRemoved(internalPosition); + compatibilityDataSizeChanged(0); + notifyItemRangeChanged(internalPosition, mData.size() - internalPosition); + } + + /** + * change data + */ + public void setData(@IntRange(from = 0) int index, @NonNull T data) { + mData.set(index, data); + notifyItemChanged(index + getHeaderLayoutCount()); + } + + /** + * add new data in to certain location + * + * @param position + */ + public void addData(@IntRange(from = 0) int position, @NonNull List data) { + mData.addAll(position, data); + notifyItemRangeInserted(position + getHeaderLayoutCount(), data.size()); + compatibilityDataSizeChanged(data.size()); + } + + /** + * additional data; + * + * @param newData + */ + public void addData(@NonNull List newData) { + this.mData.addAll(newData); + notifyItemRangeInserted(mData.size() - newData.size() + getHeaderLayoutCount(), newData.size()); + compatibilityDataSizeChanged(newData.size()); + } + + /** + * compatible getLoadMoreViewCount and getEmptyViewCount may change + * + * @param size Need compatible data size + */ + private void compatibilityDataSizeChanged(int size) { + final int dataSize = mData == null ? 0 : mData.size(); + if (dataSize == size) { + notifyDataSetChanged(); + } + } + + /** + * Get the data of list + * + * @return + */ + @NonNull + public List getData() { + return mData; + } + + /** + * Get the data item associated with the specified position in the data set. + * + * @param position Position of the item whose data we want within the adapter's + * data set. + * @return The data at the specified position. + */ + @Nullable + public T getItem(@IntRange(from = 0) int position) { + if (position < mData.size()) + return mData.get(position); + else + return null; + } + + /** + * if setHeadView will be return 1 if not will be return 0. + * notice: Deprecated! Use {@link ViewGroup#getChildCount()} of {@link #getHeaderLayout()} to replace. + * + * @return + */ + @Deprecated + public int getHeaderViewsCount() { + return getHeaderLayoutCount(); + } + + /** + * if mFooterLayout will be return 1 or not will be return 0. + * notice: Deprecated! Use {@link ViewGroup#getChildCount()} of {@link #getFooterLayout()} to replace. + * + * @return + */ + @Deprecated + public int getFooterViewsCount() { + return getFooterLayoutCount(); + } + + /** + * if addHeaderView will be return 1, if not will be return 0 + */ + public int getHeaderLayoutCount() { + if (mHeaderLayout == null || mHeaderLayout.getChildCount() == 0) { + return 0; + } + return 1; + } + + /** + * if addFooterView will be return 1, if not will be return 0 + */ + public int getFooterLayoutCount() { + if (mFooterLayout == null || mFooterLayout.getChildCount() == 0) { + return 0; + } + return 1; + } + + /** + * if show empty view will be return 1 or not will be return 0 + * + * @return + */ + public int getEmptyViewCount() { + if (mEmptyLayout == null || mEmptyLayout.getChildCount() == 0) { + return 0; + } + if (!mIsUseEmpty) { + return 0; + } + if (mData.size() != 0) { + return 0; + } + return 1; + } + + @Override + public int getItemCount() { + int count; + if (getEmptyViewCount() == 1) { + count = 1; + if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) { + count++; + } + if (mFootAndEmptyEnable && getFooterLayoutCount() != 0) { + count++; + } + } else { + count = getHeaderLayoutCount() + mData.size() + getFooterLayoutCount() + getLoadMoreViewCount(); + } + return count; + } + + @Override + public int getItemViewType(int position) { + if (getEmptyViewCount() == 1) { + boolean header = mHeadAndEmptyEnable && getHeaderLayoutCount() != 0; + switch (position) { + case 0: + if (header) { + return HEADER_VIEW; + } else { + return EMPTY_VIEW; + } + case 1: + if (header) { + return EMPTY_VIEW; + } else { + return FOOTER_VIEW; + } + case 2: + return FOOTER_VIEW; + default: + return EMPTY_VIEW; + } + } + int numHeaders = getHeaderLayoutCount(); + if (position < numHeaders) { + return HEADER_VIEW; + } else { + int adjPosition = position - numHeaders; + int adapterCount = mData.size(); + if (adjPosition < adapterCount) { + return getDefItemViewType(adjPosition); + } else { + adjPosition = adjPosition - adapterCount; + int numFooters = getFooterLayoutCount(); + if (adjPosition < numFooters) { + return FOOTER_VIEW; + } else { + return LOADING_VIEW; + } + } + } + } + + protected int getDefItemViewType(int position) { + if (mMultiTypeDelegate != null) { + return mMultiTypeDelegate.getDefItemViewType(mData, position); + } + return super.getItemViewType(position); + } + + @Override + public K onCreateViewHolder(ViewGroup parent, int viewType) { + K baseViewHolder = null; + this.mContext = parent.getContext(); + this.mLayoutInflater = LayoutInflater.from(mContext); + switch (viewType) { + case LOADING_VIEW: + baseViewHolder = getLoadingView(parent); + break; + case HEADER_VIEW: + baseViewHolder = createBaseViewHolder(mHeaderLayout); + break; + case EMPTY_VIEW: + baseViewHolder = createBaseViewHolder(mEmptyLayout); + break; + case FOOTER_VIEW: + baseViewHolder = createBaseViewHolder(mFooterLayout); + break; + default: + baseViewHolder = onCreateDefViewHolder(parent, viewType); + bindViewClickListener(baseViewHolder); + } + baseViewHolder.setAdapter(this); + return baseViewHolder; + + } + + + private K getLoadingView(ViewGroup parent) { + View view = getItemView(mLoadMoreView.getLayoutId(), parent); + K holder = createBaseViewHolder(view); + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mLoadMoreView.getLoadMoreStatus() == LoadMoreView.STATUS_FAIL) { + mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT); + notifyItemChanged(getHeaderLayoutCount() + mData.size() + getFooterLayoutCount()); + } + } + }); + return holder; + } + + /** + * Called when a view created by this adapter has been attached to a window. + * simple to solve item will layout using all + * {@link #setFullSpan(RecyclerView.ViewHolder)} + * + * @param holder + */ + @Override + public void onViewAttachedToWindow(K holder) { + super.onViewAttachedToWindow(holder); + int type = holder.getItemViewType(); + if (type == EMPTY_VIEW || type == HEADER_VIEW || type == FOOTER_VIEW || type == LOADING_VIEW) { + setFullSpan(holder); + } else { + addAnimation(holder); + } + } + + /** + * When set to true, the item will layout using all span area. That means, if orientation + * is vertical, the view will have full width; if orientation is horizontal, the view will + * have full height. + * if the hold view use StaggeredGridLayoutManager they should using all span area + * + * @param holder True if this item should traverse all spans. + */ + protected void setFullSpan(RecyclerView.ViewHolder holder) { + if (holder.itemView.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams) { + StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) holder + .itemView.getLayoutParams(); + params.setFullSpan(true); + } + } + + @Override + public void onAttachedToRecyclerView(final RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); + if (manager instanceof GridLayoutManager) { + final GridLayoutManager gridManager = ((GridLayoutManager) manager); + gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + int type = getItemViewType(position); + if (type == HEADER_VIEW && isHeaderViewAsFlow()) { + return 1; + } + if (type == FOOTER_VIEW && isFooterViewAsFlow()) { + return 1; + } + if (mSpanSizeLookup == null) { + return isFixedViewType(type) ? gridManager.getSpanCount() : 1; + } else { + return (isFixedViewType(type)) ? gridManager.getSpanCount() : mSpanSizeLookup.getSpanSize(gridManager, + position - getHeaderLayoutCount()); + } + } + + + }); + } + } + + protected boolean isFixedViewType(int type) { + return type == EMPTY_VIEW || type == HEADER_VIEW || type == FOOTER_VIEW || type == + LOADING_VIEW; + } + + /** + * if asFlow is true, footer/header will arrange like normal item view. + * only works when use {@link GridLayoutManager},and it will ignore span size. + */ + private boolean headerViewAsFlow, footerViewAsFlow; + + public void setHeaderViewAsFlow(boolean headerViewAsFlow) { + this.headerViewAsFlow = headerViewAsFlow; + } + + public boolean isHeaderViewAsFlow() { + return headerViewAsFlow; + } + + public void setFooterViewAsFlow(boolean footerViewAsFlow) { + this.footerViewAsFlow = footerViewAsFlow; + } + + public boolean isFooterViewAsFlow() { + return footerViewAsFlow; + } + + private SpanSizeLookup mSpanSizeLookup; + + public interface SpanSizeLookup { + int getSpanSize(GridLayoutManager gridLayoutManager, int position); + } + + /** + * @param spanSizeLookup instance to be used to query number of spans occupied by each item + */ + public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) { + this.mSpanSizeLookup = spanSizeLookup; + } + + /** + * To bind different types of holder and solve different the bind events + * + * @param holder + * @param positions + * @see #getDefItemViewType(int) + */ + @Override + public void onBindViewHolder(K holder, int positions) { + //Do not move position, need to change before LoadMoreView binding + autoLoadMore(positions); + int viewType = holder.getItemViewType(); + + switch (viewType) { + case 0: + + convert(holder, mData.get(holder.getLayoutPosition() - getHeaderLayoutCount())); + break; + case LOADING_VIEW: + mLoadMoreView.convert(holder); + break; + case HEADER_VIEW: + break; + case EMPTY_VIEW: + break; + case FOOTER_VIEW: + break; + default: + convert(holder, mData.get(holder.getLayoutPosition() - getHeaderLayoutCount())); + break; + } + } + + private void bindViewClickListener(final BaseViewHolder baseViewHolder) { + if (baseViewHolder == null) { + return; + } + final View view = baseViewHolder.itemView; + if (view == null) { + return; + } + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (getOnItemClickListener() != null) { + + getOnItemClickListener().onItemClick(BaseQuickAdapter.this, v, baseViewHolder.getLayoutPosition() - getHeaderLayoutCount()); + } + + } + }); + view.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + return getOnItemLongClickListener() != null && + getOnItemLongClickListener().onItemLongClick(BaseQuickAdapter.this, v, baseViewHolder.getLayoutPosition() - getHeaderLayoutCount()); + } + }); + } + + private MultiTypeDelegate mMultiTypeDelegate; + + public void setMultiTypeDelegate(MultiTypeDelegate multiTypeDelegate) { + mMultiTypeDelegate = multiTypeDelegate; + } + + public MultiTypeDelegate getMultiTypeDelegate() { + return mMultiTypeDelegate; + } + + protected K onCreateDefViewHolder(ViewGroup parent, int viewType) { + int layoutId = mLayoutResId; + if (mMultiTypeDelegate != null) { + layoutId = mMultiTypeDelegate.getLayoutId(viewType); + } + return createBaseViewHolder(parent, layoutId); + } + + protected K createBaseViewHolder(ViewGroup parent, int layoutResId) { + return createBaseViewHolder(getItemView(layoutResId, parent)); + } + + /** + * if you want to use subclass of BaseViewHolder in the adapter, + * you must override the method to create new ViewHolder. + * + * @param view view + * @return new ViewHolder + */ + @SuppressWarnings("unchecked") + protected K createBaseViewHolder(View view) { + Class temp = getClass(); + Class z = null; + while (z == null && null != temp) { + z = getInstancedGenericKClass(temp); + temp = temp.getSuperclass(); + } + K k = createGenericKInstance(z, view); + return null != k ? k : (K) new BaseViewHolder(view); + } + + /** + * try to create Generic K instance + * + * @param z + * @param view + * @return + */ + @SuppressWarnings("unchecked") + private K createGenericKInstance(Class z, View view) { + try { + Constructor constructor; + String buffer = Modifier.toString(z.getModifiers()); + String className = z.getName(); + // inner and unstatic class + if (className.contains("$") && !buffer.contains("static")) { + constructor = z.getDeclaredConstructor(getClass(), View.class); + return (K) constructor.newInstance(this, view); + } else { + constructor = z.getDeclaredConstructor(View.class); + return (K) constructor.newInstance(view); + } + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } + + /** + * get generic parameter K + * + * @param z + * @return + */ + private Class getInstancedGenericKClass(Class z) { + Type type = z.getGenericSuperclass(); + if (type instanceof ParameterizedType) { + Type[] types = ((ParameterizedType) type).getActualTypeArguments(); + for (Type temp : types) { + if (temp instanceof Class) { + Class tempClass = (Class) temp; + if (BaseViewHolder.class.isAssignableFrom(tempClass)) { + return tempClass; + } + } + } + } + return null; + } + + /** + * Return root layout of header + */ + + public LinearLayout getHeaderLayout() { + return mHeaderLayout; + } + + /** + * Return root layout of footer + */ + public LinearLayout getFooterLayout() { + return mFooterLayout; + } + + /** + * Append header to the rear of the mHeaderLayout. + * + * @param header + */ + public int addHeaderView(View header) { + return addHeaderView(header, -1); + } + + /** + * Add header view to mHeaderLayout and set header view position in mHeaderLayout. + * When index = -1 or index >= child count in mHeaderLayout, + * the effect of this method is the same as that of {@link #addHeaderView(View)}. + * + * @param header + * @param index the position in mHeaderLayout of this header. + * When index = -1 or index >= child count in mHeaderLayout, + * the effect of this method is the same as that of {@link #addHeaderView(View)}. + */ + public int addHeaderView(View header, int index) { + return addHeaderView(header, index, LinearLayout.VERTICAL); + } + + /** + * @param header + * @param index + * @param orientation + */ + public int addHeaderView(View header, int index, int orientation) { + if (mHeaderLayout == null) { + mHeaderLayout = new LinearLayout(header.getContext()); + if (orientation == LinearLayout.VERTICAL) { + mHeaderLayout.setOrientation(LinearLayout.VERTICAL); + mHeaderLayout.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT)); + } else { + mHeaderLayout.setOrientation(LinearLayout.HORIZONTAL); + mHeaderLayout.setLayoutParams(new LayoutParams(WRAP_CONTENT, MATCH_PARENT)); + } + } + final int childCount = mHeaderLayout.getChildCount(); + if (index < 0 || index > childCount) { + index = childCount; + } + mHeaderLayout.addView(header, index); + if (mHeaderLayout.getChildCount() == 1) { + int position = getHeaderViewPosition(); + if (position != -1) { + notifyItemInserted(position); + } + } + return index; + } + + public int setHeaderView(View header) { + return setHeaderView(header, 0, LinearLayout.VERTICAL); + } + + public int setHeaderView(View header, int index) { + return setHeaderView(header, index, LinearLayout.VERTICAL); + } + + public int setHeaderView(View header, int index, int orientation) { + if (mHeaderLayout == null || mHeaderLayout.getChildCount() <= index) { + return addHeaderView(header, index, orientation); + } else { + mHeaderLayout.removeViewAt(index); + mHeaderLayout.addView(header, index); + return index; + } + } + + /** + * Append footer to the rear of the mFooterLayout. + * + * @param footer + */ + public int addFooterView(View footer) { + return addFooterView(footer, -1, LinearLayout.VERTICAL); + } + + public int addFooterView(View footer, int index) { + return addFooterView(footer, index, LinearLayout.VERTICAL); + } + + /** + * Add footer view to mFooterLayout and set footer view position in mFooterLayout. + * When index = -1 or index >= child count in mFooterLayout, + * the effect of this method is the same as that of {@link #addFooterView(View)}. + * + * @param footer + * @param index the position in mFooterLayout of this footer. + * When index = -1 or index >= child count in mFooterLayout, + * the effect of this method is the same as that of {@link #addFooterView(View)}. + */ + public int addFooterView(View footer, int index, int orientation) { + if (mFooterLayout == null) { + mFooterLayout = new LinearLayout(footer.getContext()); + if (orientation == LinearLayout.VERTICAL) { + mFooterLayout.setOrientation(LinearLayout.VERTICAL); + mFooterLayout.setLayoutParams(new LayoutParams(MATCH_PARENT, WRAP_CONTENT)); + } else { + mFooterLayout.setOrientation(LinearLayout.HORIZONTAL); + mFooterLayout.setLayoutParams(new LayoutParams(WRAP_CONTENT, MATCH_PARENT)); + } + } + final int childCount = mFooterLayout.getChildCount(); + if (index < 0 || index > childCount) { + index = childCount; + } + mFooterLayout.addView(footer, index); + if (mFooterLayout.getChildCount() == 1) { + int position = getFooterViewPosition(); + if (position != -1) { + notifyItemInserted(position); + } + } + return index; + } + + public int setFooterView(View header) { + return setFooterView(header, 0, LinearLayout.VERTICAL); + } + + public int setFooterView(View header, int index) { + return setFooterView(header, index, LinearLayout.VERTICAL); + } + + public int setFooterView(View header, int index, int orientation) { + if (mFooterLayout == null || mFooterLayout.getChildCount() <= index) { + return addFooterView(header, index, orientation); + } else { + mFooterLayout.removeViewAt(index); + mFooterLayout.addView(header, index); + return index; + } + } + + /** + * remove header view from mHeaderLayout. + * When the child count of mHeaderLayout is 0, mHeaderLayout will be set to null. + * + * @param header + */ + public void removeHeaderView(View header) { + if (getHeaderLayoutCount() == 0) return; + + mHeaderLayout.removeView(header); + if (mHeaderLayout.getChildCount() == 0) { + int position = getHeaderViewPosition(); + if (position != -1) { + notifyItemRemoved(position); + } + } + } + + /** + * remove footer view from mFooterLayout, + * When the child count of mFooterLayout is 0, mFooterLayout will be set to null. + * + * @param footer + */ + public void removeFooterView(View footer) { + if (getFooterLayoutCount() == 0) return; + + mFooterLayout.removeView(footer); + if (mFooterLayout.getChildCount() == 0) { + int position = getFooterViewPosition(); + if (position != -1) { + notifyItemRemoved(position); + } + } + } + + /** + * remove all header view from mHeaderLayout and set null to mHeaderLayout + */ + public void removeAllHeaderView() { + if (getHeaderLayoutCount() == 0) return; + + mHeaderLayout.removeAllViews(); + int position = getHeaderViewPosition(); + if (position != -1) { + notifyItemRemoved(position); + } + } + + /** + * remove all footer view from mFooterLayout and set null to mFooterLayout + */ + public void removeAllFooterView() { + if (getFooterLayoutCount() == 0) return; + + mFooterLayout.removeAllViews(); + int position = getFooterViewPosition(); + if (position != -1) { + notifyItemRemoved(position); + } + } + + private int getHeaderViewPosition() { + //Return to header view notify position + if (getEmptyViewCount() == 1) { + if (mHeadAndEmptyEnable) { + return 0; + } + } else { + return 0; + } + return -1; + } + + private int getFooterViewPosition() { + //Return to footer view notify position + if (getEmptyViewCount() == 1) { + int position = 1; + if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) { + position++; + } + if (mFootAndEmptyEnable) { + return position; + } + } else { + return getHeaderLayoutCount() + mData.size(); + } + return -1; + } + + public void setEmptyView(int layoutResId, ViewGroup viewGroup) { + View view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutResId, viewGroup, false); + setEmptyView(view); + } + + /** + * bind recyclerView {@link #bindToRecyclerView(RecyclerView)} before use! + * + * @see #bindToRecyclerView(RecyclerView) + */ + public void setEmptyView(int layoutResId) { + checkNotNull(); + setEmptyView(layoutResId, getRecyclerView()); + } + + public void setEmptyView(View emptyView) { + boolean insert = false; + if (mEmptyLayout == null) { + mEmptyLayout = new FrameLayout(emptyView.getContext()); + final LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + final ViewGroup.LayoutParams lp = emptyView.getLayoutParams(); + if (lp != null) { + layoutParams.width = lp.width; + layoutParams.height = lp.height; + } + mEmptyLayout.setLayoutParams(layoutParams); + insert = true; + } + mEmptyLayout.removeAllViews(); + mEmptyLayout.addView(emptyView); + mIsUseEmpty = true; + if (insert) { + if (getEmptyViewCount() == 1) { + int position = 0; + if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) { + position++; + } + notifyItemInserted(position); + } + } + } + + /** + * Call before {@link RecyclerView#setAdapter(RecyclerView.Adapter)} + * + * @param isHeadAndEmpty false will not show headView if the data is empty true will show emptyView and headView + */ + public void setHeaderAndEmpty(boolean isHeadAndEmpty) { + setHeaderFooterEmpty(isHeadAndEmpty, false); + } + + /** + * set emptyView show if adapter is empty and want to show headview and footview + * Call before {@link RecyclerView#setAdapter(RecyclerView.Adapter)} + * + * @param isHeadAndEmpty + * @param isFootAndEmpty + */ + public void setHeaderFooterEmpty(boolean isHeadAndEmpty, boolean isFootAndEmpty) { + mHeadAndEmptyEnable = isHeadAndEmpty; + mFootAndEmptyEnable = isFootAndEmpty; + } + + /** + * Set whether to use empty view + * + * @param isUseEmpty + */ + public void isUseEmpty(boolean isUseEmpty) { + mIsUseEmpty = isUseEmpty; + } + + /** + * When the current adapter is empty, the BaseQuickAdapter can display a special view + * called the empty view. The empty view is used to provide feedback to the user + * that no data is available in this AdapterView. + * + * @return The view to show if the adapter is empty. + */ + public View getEmptyView() { + return mEmptyLayout; + } + + private int mPreLoadNumber = 1; + + @Deprecated + public void setAutoLoadMoreSize(int preLoadNumber) { + setPreLoadNumber(preLoadNumber); + } + + public void setPreLoadNumber(int preLoadNumber) { + if (preLoadNumber > 1) { + mPreLoadNumber = preLoadNumber; + } + } + + private void autoLoadMore(int position) { + if (getLoadMoreViewCount() == 0) { + return; + } + if (position < getItemCount() - mPreLoadNumber) { + return; + } + if (mLoadMoreView.getLoadMoreStatus() != LoadMoreView.STATUS_DEFAULT) { + return; + } + mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_LOADING); + if (!mLoading) { + mLoading = true; + if (getRecyclerView() != null) { + getRecyclerView().post(new Runnable() { + @Override + public void run() { + mRequestLoadMoreListener.onLoadMoreRequested(); + } + }); + } else { + mRequestLoadMoreListener.onLoadMoreRequested(); + } + } + } + + + /** + * add animation when you want to show time + * + * @param holder + */ + private void addAnimation(RecyclerView.ViewHolder holder) { + if (mOpenAnimationEnable) { + if (!mFirstOnlyEnable || holder.getLayoutPosition() > mLastPosition) { + BaseAnimation animation = null; + if (mCustomAnimation != null) { + animation = mCustomAnimation; + } else { + animation = mSelectAnimation; + } + for (Animator anim : animation.getAnimators(holder.itemView)) { + startAnim(anim, holder.getLayoutPosition()); + } + mLastPosition = holder.getLayoutPosition(); + } + } + } + + /** + * set anim to start when loading + * + * @param anim + * @param index + */ + protected void startAnim(Animator anim, int index) { + anim.setDuration(mDuration).start(); + anim.setInterpolator(mInterpolator); + } + + /** + * @param layoutResId ID for an XML layout resource to load + * @param parent Optional view to be the parent of the generated hierarchy or else simply an object that + * provides a set of LayoutParams values for root of the returned + * hierarchy + * @return view will be return + */ + protected View getItemView(@LayoutRes int layoutResId, ViewGroup parent) { + return mLayoutInflater.inflate(layoutResId, parent, false); + } + + + public interface RequestLoadMoreListener { + + void onLoadMoreRequested(); + + } + + + /** + * Set the view animation type. + * + * @param animationType One of {@link #ALPHAIN}, {@link #SCALEIN}, {@link #SLIDEIN_BOTTOM}, + * {@link #SLIDEIN_LEFT}, {@link #SLIDEIN_RIGHT}. + */ + public void openLoadAnimation(@AnimationType int animationType) { + this.mOpenAnimationEnable = true; + mCustomAnimation = null; + switch (animationType) { + case ALPHAIN: + mSelectAnimation = new AlphaInAnimation(); + break; + case SCALEIN: + mSelectAnimation = new ScaleInAnimation(); + break; + case SLIDEIN_BOTTOM: + mSelectAnimation = new SlideInBottomAnimation(); + break; + case SLIDEIN_LEFT: + mSelectAnimation = new SlideInLeftAnimation(); + break; + case SLIDEIN_RIGHT: + mSelectAnimation = new SlideInRightAnimation(); + break; + default: + break; + } + } + + /** + * Set Custom ObjectAnimator + * + * @param animation ObjectAnimator + */ + public void openLoadAnimation(BaseAnimation animation) { + this.mOpenAnimationEnable = true; + this.mCustomAnimation = animation; + } + + /** + * To open the animation when loading + */ + public void openLoadAnimation() { + this.mOpenAnimationEnable = true; + } + + /** + * {@link #addAnimation(RecyclerView.ViewHolder)} + * + * @param firstOnly true just show anim when first loading false show anim when load the data every time + */ + public void isFirstOnly(boolean firstOnly) { + this.mFirstOnlyEnable = firstOnly; + } + + /** + * Implement this method and use the helper to adapt the view to the given item. + * + * @param helper A fully initialized helper. + * @param item The item that needs to be displayed. + */ + protected abstract void convert(K helper, T item); + + /** + * get the specific view by position,e.g. getViewByPosition(2, R.id.textView) + *

+ * bind recyclerView {@link #bindToRecyclerView(RecyclerView)} before use! + * + * @see #bindToRecyclerView(RecyclerView) + */ + public View getViewByPosition(int position, @IdRes int viewId) { + checkNotNull(); + return getViewByPosition(getRecyclerView(), position, viewId); + } + + public View getViewByPosition(RecyclerView recyclerView, int position, @IdRes int viewId) { + if (recyclerView == null) { + return null; + } + BaseViewHolder viewHolder = (BaseViewHolder) recyclerView.findViewHolderForLayoutPosition(position); + if (viewHolder == null) { + return null; + } + return viewHolder.getView(viewId); + } + + /** + * Get the row id associated with the specified position in the list. + * + * @param position The position of the item within the adapter's data set whose row id we want. + * @return The id of the item at the specified position. + */ + @Override + public long getItemId(int position) { + return position; + } + + @SuppressWarnings("unchecked") + private int recursiveExpand(int position, @NonNull List list) { + int count = 0; + int pos = position + list.size() - 1; + for (int i = list.size() - 1; i >= 0; i--, pos--) { + if (list.get(i) instanceof IExpandable) { + IExpandable item = (IExpandable) list.get(i); + if (item.isExpanded() && hasSubItems(item)) { + List subList = item.getSubItems(); + mData.addAll(pos + 1, subList); + int subItemCount = recursiveExpand(pos + 1, subList); + count += subItemCount; + } + } + } + return count; + + } + + /** + * Expand an expandable item + * + * @param position position of the item + * @param animate expand items with animation + * @param shouldNotify notify the RecyclerView to rebind items, false if you want to do it + * yourself. + * @return the number of items that have been added. + */ + @SuppressWarnings("unchecked") + public int expand(@IntRange(from = 0) int position, boolean animate, boolean shouldNotify) { + position -= getHeaderLayoutCount(); + + IExpandable expandable = getExpandableItem(position); + if (expandable == null) { + return 0; + } + if (!hasSubItems(expandable)) { + expandable.setExpanded(false); + return 0; + } + int subItemCount = 0; + if (!expandable.isExpanded()) { + List list = expandable.getSubItems(); + mData.addAll(position + 1, list); + subItemCount += recursiveExpand(position + 1, list); + + expandable.setExpanded(true); + subItemCount += list.size(); + } + int parentPos = position + getHeaderLayoutCount(); + if (shouldNotify) { + if (animate) { + notifyItemChanged(parentPos); + notifyItemRangeInserted(parentPos + 1, subItemCount); + } else { + notifyDataSetChanged(); + } + } + return subItemCount; + } + + /** + * Expand an expandable item + * + * @param position position of the item, which includes the header layout count. + * @param animate expand items with animation + * @return the number of items that have been added. + */ + public int expand(@IntRange(from = 0) int position, boolean animate) { + return expand(position, animate, true); + } + + /** + * Expand an expandable item with animation. + * + * @param position position of the item, which includes the header layout count. + * @return the number of items that have been added. + */ + public int expand(@IntRange(from = 0) int position) { + return expand(position, true, true); + } + + public int expandAll(int position, boolean animate, boolean notify) { + position -= getHeaderLayoutCount(); + + T endItem = null; + if (position + 1 < this.mData.size()) { + endItem = getItem(position + 1); + } + + IExpandable expandable = getExpandableItem(position); + if (expandable == null || !hasSubItems(expandable)) { + return 0; + } + + int count = expand(position + getHeaderLayoutCount(), false, false); + for (int i = position + 1; i < this.mData.size(); i++) { + T item = getItem(i); + + if (item == endItem) { + break; + } + if (isExpandable(item)) { + count += expand(i + getHeaderLayoutCount(), false, false); + } + } + + if (notify) { + if (animate) { + notifyItemRangeInserted(position + getHeaderLayoutCount() + 1, count); + } else { + notifyDataSetChanged(); + } + } + return count; + } + + /** + * expand the item and all its subItems + * + * @param position position of the item, which includes the header layout count. + * @param init whether you are initializing the recyclerView or not. + * if true, it won't notify recyclerView to redraw UI. + * @return the number of items that have been added to the adapter. + */ + public int expandAll(int position, boolean init) { + return expandAll(position, true, !init); + } + + public void expandAll() { + for (int i = mData.size() - 1; i >= 0; i--) { + expandAll(i, false, false); + } + } + + @SuppressWarnings("unchecked") + private int recursiveCollapse(@IntRange(from = 0) int position) { + T item = getItem(position); + if (!isExpandable(item)) { + return 0; + } + IExpandable expandable = (IExpandable) item; + int subItemCount = 0; + if (expandable.isExpanded()) { + List subItems = expandable.getSubItems(); + for (int i = subItems.size() - 1; i >= 0; i--) { + T subItem = subItems.get(i); + int pos = getItemPosition(subItem); + if (pos < 0) { + continue; + } + if (subItem instanceof IExpandable) { + subItemCount += recursiveCollapse(pos); + } + mData.remove(pos); + subItemCount++; + } + } + return subItemCount; + } + + /** + * Collapse an expandable item that has been expanded.. + * + * @param position the position of the item, which includes the header layout count. + * @param animate collapse with animation or not. + * @param notify notify the recyclerView refresh UI or not. + * @return the number of subItems collapsed. + */ + public int collapse(@IntRange(from = 0) int position, boolean animate, boolean notify) { + position -= getHeaderLayoutCount(); + + IExpandable expandable = getExpandableItem(position); + if (expandable == null) { + return 0; + } + int subItemCount = recursiveCollapse(position); + expandable.setExpanded(false); + int parentPos = position + getHeaderLayoutCount(); + if (notify) { + if (animate) { + notifyItemChanged(parentPos); + notifyItemRangeRemoved(parentPos + 1, subItemCount); + } else { + notifyDataSetChanged(); + } + } + return subItemCount; + } + + /** + * Collapse an expandable item that has been expanded.. + * + * @param position the position of the item, which includes the header layout count. + * @return the number of subItems collapsed. + */ + public int collapse(@IntRange(from = 0) int position) { + return collapse(position, true, true); + } + + /** + * Collapse an expandable item that has been expanded.. + * + * @param position the position of the item, which includes the header layout count. + * @return the number of subItems collapsed. + */ + public int collapse(@IntRange(from = 0) int position, boolean animate) { + return collapse(position, animate, true); + } + + private int getItemPosition(T item) { + return item != null && mData != null && !mData.isEmpty() ? mData.indexOf(item) : -1; + } + + private boolean hasSubItems(IExpandable item) { + if (item == null) { + return false; + } + List list = item.getSubItems(); + return list != null && list.size() > 0; + } + + public boolean isExpandable(T item) { + return item != null && item instanceof IExpandable; + } + + private IExpandable getExpandableItem(int position) { + T item = getItem(position); + if (isExpandable(item)) { + return (IExpandable) item; + } else { + return null; + } + } + + /** + * Get the parent item position of the IExpandable item + * + * @return return the closest parent item position of the IExpandable. + * if the IExpandable item's level is 0, return itself position. + * if the item's level is negative which mean do not implement this, return a negative + * if the item is not exist in the data list, return a negative. + */ + public int getParentPosition(@NonNull T item) { + int position = getItemPosition(item); + if (position == -1) { + return -1; + } + + // if the item is IExpandable, return a closest IExpandable item position whose level smaller than this. + // if it is not, return the closest IExpandable item position whose level is not negative + int level; + if (item instanceof IExpandable) { + level = ((IExpandable) item).getLevel(); + } else { + level = Integer.MAX_VALUE; + } + if (level == 0) { + return position; + } else if (level == -1) { + return -1; + } + + for (int i = position; i >= 0; i--) { + T temp = mData.get(i); + if (temp instanceof IExpandable) { + IExpandable expandable = (IExpandable) temp; + if (expandable.getLevel() >= 0 && expandable.getLevel() < level) { + return i; + } + } + } + return -1; + } + + /** + * Interface definition for a callback to be invoked when an itemchild in this + * view has been clicked + */ + public interface OnItemChildClickListener { + /** + * callback method to be invoked when an item in this view has been + * click and held + * + * @param view The view whihin the ItemView that was clicked + * @param position The position of the view int the adapter + */ + void onItemChildClick(BaseQuickAdapter adapter, View view, int position); + } + + + /** + * Interface definition for a callback to be invoked when an childView in this + * view has been clicked and held. + */ + public interface OnItemChildLongClickListener { + /** + * callback method to be invoked when an item in this view has been + * click and held + * + * @param view The childView whihin the itemView that was clicked and held. + * @param position The position of the view int the adapter + * @return true if the callback consumed the long click ,false otherwise + */ + boolean onItemChildLongClick(BaseQuickAdapter adapter, View view, int position); + } + + /** + * Interface definition for a callback to be invoked when an item in this + * view has been clicked and held. + */ + public interface OnItemLongClickListener { + /** + * callback method to be invoked when an item in this view has been + * click and held + * + * @param adapter the adpater + * @param view The view whihin the RecyclerView that was clicked and held. + * @param position The position of the view int the adapter + * @return true if the callback consumed the long click ,false otherwise + */ + boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position); + } + + + /** + * Interface definition for a callback to be invoked when an item in this + * RecyclerView itemView has been clicked. + */ + public interface OnItemClickListener { + + /** + * Callback method to be invoked when an item in this RecyclerView has + * been clicked. + * + * @param adapter the adpater + * @param view The itemView within the RecyclerView that was clicked (this + * will be a view provided by the adapter) + * @param position The position of the view in the adapter. + */ + void onItemClick(BaseQuickAdapter adapter, View view, int position); + } + + /** + * Register a callback to be invoked when an item in this RecyclerView has + * been clicked. + * + * @param listener The callback that will be invoked. + */ + public void setOnItemClickListener(@Nullable OnItemClickListener listener) { + mOnItemClickListener = listener; + } + + /** + * Register a callback to be invoked when an itemchild in View has + * been clicked + * + * @param listener The callback that will run + */ + public void setOnItemChildClickListener(OnItemChildClickListener listener) { + mOnItemChildClickListener = listener; + } + + /** + * Register a callback to be invoked when an item in this RecyclerView has + * been long clicked and held + * + * @param listener The callback that will run + */ + public void setOnItemLongClickListener(OnItemLongClickListener listener) { + mOnItemLongClickListener = listener; + } + + /** + * Register a callback to be invoked when an itemchild in this View has + * been long clicked and held + * + * @param listener The callback that will run + */ + public void setOnItemChildLongClickListener(OnItemChildLongClickListener listener) { + mOnItemChildLongClickListener = listener; + } + + + /** + * @return The callback to be invoked with an item in this RecyclerView has + * been long clicked and held, or null id no callback as been set. + */ + public final OnItemLongClickListener getOnItemLongClickListener() { + return mOnItemLongClickListener; + } + + /** + * @return The callback to be invoked with an item in this RecyclerView has + * been clicked and held, or null id no callback as been set. + */ + public final OnItemClickListener getOnItemClickListener() { + return mOnItemClickListener; + } + + /** + * @return The callback to be invoked with an itemchild in this RecyclerView has + * been clicked, or null id no callback has been set. + */ + @Nullable + public final OnItemChildClickListener getOnItemChildClickListener() { + return mOnItemChildClickListener; + } + + /** + * @return The callback to be invoked with an itemChild in this RecyclerView has + * been long clicked, or null id no callback has been set. + */ + @Nullable + public final OnItemChildLongClickListener getOnItemChildLongClickListener() { + return mOnItemChildLongClickListener; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseSectionQuickAdapter.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseSectionQuickAdapter.java new file mode 100644 index 0000000..5d5e5a3 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseSectionQuickAdapter.java @@ -0,0 +1,65 @@ +package com.xusangbo.basemoudle.weight.baseadapter; + +import android.view.ViewGroup; + + +import com.xusangbo.basemoudle.weight.baseadapter.entity.SectionEntity; + +import java.util.List; + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public abstract class BaseSectionQuickAdapter extends BaseQuickAdapter { + + + protected int mSectionHeadResId; + protected static final int SECTION_HEADER_VIEW = 0x00000444; + + /** + * Same as QuickAdapter#QuickAdapter(Context,int) but with + * some initialization data. + * + * @param sectionHeadResId The section head layout id for each item + * @param layoutResId The layout resource id of each item. + * @param data A new list is created out of this one to avoid mutable list + */ + public BaseSectionQuickAdapter(int layoutResId, int sectionHeadResId, List data) { + super(layoutResId, data); + this.mSectionHeadResId = sectionHeadResId; + } + + @Override + protected int getDefItemViewType(int position) { + return mData.get(position).isHeader ? SECTION_HEADER_VIEW : 0; + } + + @Override + protected K onCreateDefViewHolder(ViewGroup parent, int viewType) { + if (viewType == SECTION_HEADER_VIEW) + return createBaseViewHolder(getItemView(mSectionHeadResId, parent)); + + return super.onCreateDefViewHolder(parent, viewType); + } + + @Override + protected boolean isFixedViewType(int type) { + return super.isFixedViewType(type)|| type == SECTION_HEADER_VIEW; + } + + @Override + public void onBindViewHolder(K holder, int positions) { + switch (holder.getItemViewType()) { + case SECTION_HEADER_VIEW: + setFullSpan(holder); + convertHead(holder, mData.get(holder.getLayoutPosition() - getHeaderLayoutCount())); + break; + default: + super.onBindViewHolder(holder, positions); + break; + } + } + + protected abstract void convertHead(K helper, T item); + +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseViewHolder.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseViewHolder.java new file mode 100644 index 0000000..e1774c4 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/BaseViewHolder.java @@ -0,0 +1,599 @@ +/** + * Copyright 2013 Joan Zapata + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.xusangbo.basemoudle.weight.baseadapter; + +import android.graphics.Bitmap; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.ColorInt; +import android.support.annotation.DrawableRes; +import android.support.annotation.IdRes; +import android.support.annotation.StringRes; +import android.support.v7.widget.RecyclerView; +import android.text.util.Linkify; +import android.util.SparseArray; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.widget.Adapter; +import android.widget.AdapterView; +import android.widget.Checkable; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RatingBar; +import android.widget.TextView; + +import java.util.HashSet; +import java.util.LinkedHashSet; + + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public class BaseViewHolder extends RecyclerView.ViewHolder { + + /** + * Views indexed with their IDs + */ + private final SparseArray views; + + public HashSet getNestViews() { + return nestViews; + } + + private final HashSet nestViews; + + private final LinkedHashSet childClickViewIds; + + private final LinkedHashSet itemChildLongClickViewIds; + private BaseQuickAdapter adapter; + /** + * use itemView instead + */ + @Deprecated + public View convertView; + + /** + * Package private field to retain the associated user object and detect a change + */ + Object associatedObject; + + + public BaseViewHolder(final View view) { + super(view); + this.views = new SparseArray<>(); + this.childClickViewIds = new LinkedHashSet<>(); + this.itemChildLongClickViewIds = new LinkedHashSet<>(); + this.nestViews = new HashSet<>(); + convertView = view; + + + } + + private int getClickPosition() { + return getLayoutPosition() - adapter.getHeaderLayoutCount(); + } + + public HashSet getItemChildLongClickViewIds() { + return itemChildLongClickViewIds; + } + + public HashSet getChildClickViewIds() { + return childClickViewIds; + } + + /** + * use itemView instead + * + * @return the ViewHolder root view + */ + @Deprecated + public View getConvertView() { + + return convertView; + } + + /** + * Will set the text of a TextView. + * + * @param viewId The view id. + * @param value The text to put in the text view. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setText(@IdRes int viewId, CharSequence value) { + TextView view = getView(viewId); + view.setText(value); + return this; + } + + public BaseViewHolder setText(@IdRes int viewId, @StringRes int strId) { + TextView view = getView(viewId); + view.setText(strId); + return this; + } + + /** + * Will set the image of an ImageView from a resource id. + * + * @param viewId The view id. + * @param imageResId The image resource id. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setImageResource(@IdRes int viewId, @DrawableRes int imageResId) { + ImageView view = getView(viewId); + view.setImageResource(imageResId); + return this; + } + + /** + * Will set background color of a view. + * + * @param viewId The view id. + * @param color A color, not a resource id. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setBackgroundColor(@IdRes int viewId, @ColorInt int color) { + View view = getView(viewId); + view.setBackgroundColor(color); + return this; + } + + /** + * Will set background of a view. + * + * @param viewId The view id. + * @param backgroundRes A resource to use as a background. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setBackgroundRes(@IdRes int viewId, @DrawableRes int backgroundRes) { + View view = getView(viewId); + view.setBackgroundResource(backgroundRes); + return this; + } + + /** + * Will set text color of a TextView. + * + * @param viewId The view id. + * @param textColor The text color (not a resource id). + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTextColor(@IdRes int viewId, @ColorInt int textColor) { + TextView view = getView(viewId); + view.setTextColor(textColor); + return this; + } + + + /** + * Will set the image of an ImageView from a drawable. + * + * @param viewId The view id. + * @param drawable The image drawable. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setImageDrawable(@IdRes int viewId, Drawable drawable) { + ImageView view = getView(viewId); + view.setImageDrawable(drawable); + return this; + } + + /** + * Add an action to set the image of an image view. Can be called multiple times. + */ + public BaseViewHolder setImageBitmap(@IdRes int viewId, Bitmap bitmap) { + ImageView view = getView(viewId); + view.setImageBitmap(bitmap); + return this; + } + + /** + * Add an action to set the alpha of a view. Can be called multiple times. + * Alpha between 0-1. + */ + public BaseViewHolder setAlpha(@IdRes int viewId, float value) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + getView(viewId).setAlpha(value); + } else { + // Pre-honeycomb hack to set Alpha value + AlphaAnimation alpha = new AlphaAnimation(value, value); + alpha.setDuration(0); + alpha.setFillAfter(true); + getView(viewId).startAnimation(alpha); + } + return this; + } + + /** + * Set a view visibility to VISIBLE (true) or GONE (false). + * + * @param viewId The view id. + * @param visible True for VISIBLE, false for GONE. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setVisible(@IdRes int viewId, boolean visible) { + View view = getView(viewId); + view.setVisibility(visible ? View.VISIBLE : View.GONE); + return this; + } + + /** + * Add links into a TextView. + * + * @param viewId The id of the TextView to linkify. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder linkify(@IdRes int viewId) { + TextView view = getView(viewId); + Linkify.addLinks(view, Linkify.ALL); + return this; + } + + /** + * Apply the typeface to the given viewId, and enable subpixel rendering. + */ + public BaseViewHolder setTypeface(@IdRes int viewId, Typeface typeface) { + TextView view = getView(viewId); + view.setTypeface(typeface); + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + return this; + } + + /** + * Apply the typeface to all the given viewIds, and enable subpixel rendering. + */ + public BaseViewHolder setTypeface(Typeface typeface, int... viewIds) { + for (int viewId : viewIds) { + TextView view = getView(viewId); + view.setTypeface(typeface); + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + } + return this; + } + + /** + * Sets the progress of a ProgressBar. + * + * @param viewId The view id. + * @param progress The progress. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setProgress(@IdRes int viewId, int progress) { + ProgressBar view = getView(viewId); + view.setProgress(progress); + return this; + } + + /** + * Sets the progress and max of a ProgressBar. + * + * @param viewId The view id. + * @param progress The progress. + * @param max The max value of a ProgressBar. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setProgress(@IdRes int viewId, int progress, int max) { + ProgressBar view = getView(viewId); + view.setMax(max); + view.setProgress(progress); + return this; + } + + /** + * Sets the range of a ProgressBar to 0...max. + * + * @param viewId The view id. + * @param max The max value of a ProgressBar. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setMax(@IdRes int viewId, int max) { + ProgressBar view = getView(viewId); + view.setMax(max); + return this; + } + + /** + * Sets the rating (the number of stars filled) of a RatingBar. + * + * @param viewId The view id. + * @param rating The rating. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setRating(@IdRes int viewId, float rating) { + RatingBar view = getView(viewId); + view.setRating(rating); + return this; + } + + /** + * Sets the rating (the number of stars filled) and max of a RatingBar. + * + * @param viewId The view id. + * @param rating The rating. + * @param max The range of the RatingBar to 0...max. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setRating(@IdRes int viewId, float rating, int max) { + RatingBar view = getView(viewId); + view.setMax(max); + view.setRating(rating); + return this; + } + + /** + * Sets the on click listener of the view. + * + * @param viewId The view id. + * @param listener The on click listener; + * @return The BaseViewHolder for chaining. + */ + @Deprecated + public BaseViewHolder setOnClickListener(@IdRes int viewId, View.OnClickListener listener) { + View view = getView(viewId); + view.setOnClickListener(listener); + return this; + } + + /** + * add childView id + * + * @param viewId add the child view id can support childview click + * @return if you use adapter bind listener + * @link {(adapter.setOnItemChildClickListener(listener))} + *

+ * or if you can use recyclerView.addOnItemTouch(listerer) wo also support this menthod + */ + @SuppressWarnings("unchecked") + public BaseViewHolder addOnClickListener(@IdRes final int viewId) { + childClickViewIds.add(viewId); + final View view = getView(viewId); + if (view != null) { + if (!view.isClickable()) { + view.setClickable(true); + } + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (adapter.getOnItemChildClickListener() != null) { + adapter.getOnItemChildClickListener().onItemChildClick(adapter, v, getClickPosition()); + } + } + }); + } + + return this; + } + + + /** + * set nestview id + * + * @param viewId add the child view id can support childview click + * @return + */ + public BaseViewHolder setNestView(@IdRes int viewId) { + addOnClickListener(viewId); + addOnLongClickListener(viewId); + nestViews.add(viewId); + return this; + } + + /** + * add long click view id + * + * @param viewId + * @return if you use adapter bind listener + * @link {(adapter.setOnItemChildLongClickListener(listener))} + *

+ * or if you can use recyclerView.addOnItemTouch(listerer) wo also support this menthod + */ + @SuppressWarnings("unchecked") + public BaseViewHolder addOnLongClickListener(@IdRes final int viewId) { + itemChildLongClickViewIds.add(viewId); + final View view = getView(viewId); + if (view != null) { + if (!view.isLongClickable()) { + view.setLongClickable(true); + } + view.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + return adapter.getOnItemChildLongClickListener() != null && + adapter.getOnItemChildLongClickListener().onItemChildLongClick(adapter, v, getClickPosition()); + } + }); + } + return this; + } + + + /** + * Sets the on touch listener of the view. + * + * @param viewId The view id. + * @param listener The on touch listener; + * @return The BaseViewHolder for chaining. + */ + @Deprecated + public BaseViewHolder setOnTouchListener(@IdRes int viewId, View.OnTouchListener listener) { + View view = getView(viewId); + view.setOnTouchListener(listener); + return this; + } + + /** + * Sets the on long click listener of the view. + * + * @param viewId The view id. + * @param listener The on long click listener; + * @return The BaseViewHolder for chaining. + * Please use {@link #addOnLongClickListener(int)} (adapter.setOnItemChildLongClickListener(listener))} + */ + @Deprecated + public BaseViewHolder setOnLongClickListener(@IdRes int viewId, View.OnLongClickListener listener) { + View view = getView(viewId); + view.setOnLongClickListener(listener); + return this; + } + + /** + * Sets the listview or gridview's item click listener of the view + * + * @param viewId The view id. + * @param listener The item on click listener; + * @return The BaseViewHolder for chaining. + * Please use {@link #addOnClickListener(int)} (int)} (adapter.setOnItemChildClickListener(listener))} + */ + @Deprecated + public BaseViewHolder setOnItemClickListener(@IdRes int viewId, AdapterView.OnItemClickListener listener) { + AdapterView view = getView(viewId); + view.setOnItemClickListener(listener); + return this; + } + + /** + * Sets the listview or gridview's item long click listener of the view + * + * @param viewId The view id. + * @param listener The item long click listener; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnItemLongClickListener(@IdRes int viewId, AdapterView.OnItemLongClickListener listener) { + AdapterView view = getView(viewId); + view.setOnItemLongClickListener(listener); + return this; + } + + /** + * Sets the listview or gridview's item selected click listener of the view + * + * @param viewId The view id. + * @param listener The item selected click listener; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnItemSelectedClickListener(@IdRes int viewId, AdapterView.OnItemSelectedListener listener) { + AdapterView view = getView(viewId); + view.setOnItemSelectedListener(listener); + return this; + } + + /** + * Sets the on checked change listener of the view. + * + * @param viewId The view id. + * @param listener The checked change listener of compound button. + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setOnCheckedChangeListener(@IdRes int viewId, CompoundButton.OnCheckedChangeListener listener) { + CompoundButton view = getView(viewId); + view.setOnCheckedChangeListener(listener); + return this; + } + + /** + * Sets the tag of the view. + * + * @param viewId The view id. + * @param tag The tag; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTag(@IdRes int viewId, Object tag) { + View view = getView(viewId); + view.setTag(tag); + return this; + } + + /** + * Sets the tag of the view. + * + * @param viewId The view id. + * @param key The key of tag; + * @param tag The tag; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setTag(@IdRes int viewId, int key, Object tag) { + View view = getView(viewId); + view.setTag(key, tag); + return this; + } + + /** + * Sets the checked status of a checkable. + * + * @param viewId The view id. + * @param checked The checked status; + * @return The BaseViewHolder for chaining. + */ + public BaseViewHolder setChecked(@IdRes int viewId, boolean checked) { + View view = getView(viewId); + // View unable cast to Checkable + if (view instanceof Checkable) { + ((Checkable) view).setChecked(checked); + } + return this; + } + + /** + * Sets the adapter of a adapter view. + * + * @param viewId The view id. + * @param adapter The adapter; + * @return The BaseViewHolder for chaining. + */ + @SuppressWarnings("unchecked") + public BaseViewHolder setAdapter(@IdRes int viewId, Adapter adapter) { + AdapterView view = getView(viewId); + view.setAdapter(adapter); + return this; + } + + /** + * Sets the adapter of a adapter view. + * + * @param adapter The adapter; + * @return The BaseViewHolder for chaining. + */ + protected BaseViewHolder setAdapter(BaseQuickAdapter adapter) { + this.adapter = adapter; + return this; + } + + @SuppressWarnings("unchecked") + public T getView(@IdRes int viewId) { + View view = views.get(viewId); + if (view == null) { + view = itemView.findViewById(viewId); + views.put(viewId, view); + } + return (T) view; + } + + /** + * Retrieves the last converted object on this view. + */ + public Object getAssociatedObject() { + return associatedObject; + } + + /** + * Should be called during convert + */ + public void setAssociatedObject(Object associatedObject) { + this.associatedObject = associatedObject; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/AlphaInAnimation.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/AlphaInAnimation.java new file mode 100644 index 0000000..0d07e0e --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/AlphaInAnimation.java @@ -0,0 +1,28 @@ +package com.xusangbo.basemoudle.weight.baseadapter.animation; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.view.View; + + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public class AlphaInAnimation implements BaseAnimation { + + private static final float DEFAULT_ALPHA_FROM = 0f; + private final float mFrom; + + public AlphaInAnimation() { + this(DEFAULT_ALPHA_FROM); + } + + public AlphaInAnimation(float from) { + mFrom = from; + } + + @Override + public Animator[] getAnimators(View view) { + return new Animator[]{ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f)}; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/BaseAnimation.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/BaseAnimation.java new file mode 100644 index 0000000..7355f74 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/BaseAnimation.java @@ -0,0 +1,13 @@ +package com.xusangbo.basemoudle.weight.baseadapter.animation; + +import android.animation.Animator; +import android.view.View; + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public interface BaseAnimation { + + Animator[] getAnimators(View view); + +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/ScaleInAnimation.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/ScaleInAnimation.java new file mode 100644 index 0000000..23459dc --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/ScaleInAnimation.java @@ -0,0 +1,30 @@ +package com.xusangbo.basemoudle.weight.baseadapter.animation; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.view.View; + + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public class ScaleInAnimation implements BaseAnimation { + + private static final float DEFAULT_SCALE_FROM = .5f; + private final float mFrom; + + public ScaleInAnimation() { + this(DEFAULT_SCALE_FROM); + } + + public ScaleInAnimation(float from) { + mFrom = from; + } + + @Override + public Animator[] getAnimators(View view) { + ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f); + ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", mFrom, 1f); + return new ObjectAnimator[] { scaleX, scaleY }; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInBottomAnimation.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInBottomAnimation.java new file mode 100644 index 0000000..c6b30f8 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInBottomAnimation.java @@ -0,0 +1,21 @@ +package com.xusangbo.basemoudle.weight.baseadapter.animation; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.view.View; + + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public class SlideInBottomAnimation implements BaseAnimation { + + + + @Override + public Animator[] getAnimators(View view) { + return new Animator[]{ + ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0) + }; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInLeftAnimation.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInLeftAnimation.java new file mode 100644 index 0000000..3dcdd99 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInLeftAnimation.java @@ -0,0 +1,20 @@ +package com.xusangbo.basemoudle.weight.baseadapter.animation; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.view.View; + + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public class SlideInLeftAnimation implements BaseAnimation { + + + @Override + public Animator[] getAnimators(View view) { + return new Animator[] { + ObjectAnimator.ofFloat(view, "translationX", -view.getRootView().getWidth(), 0) + }; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInRightAnimation.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInRightAnimation.java new file mode 100644 index 0000000..aecdc8c --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/animation/SlideInRightAnimation.java @@ -0,0 +1,20 @@ +package com.xusangbo.basemoudle.weight.baseadapter.animation; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.view.View; + + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public class SlideInRightAnimation implements BaseAnimation { + + + @Override + public Animator[] getAnimators(View view) { + return new Animator[]{ + ObjectAnimator.ofFloat(view, "translationX", view.getRootView().getWidth(), 0) + }; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/callback/ItemDragAndSwipeCallback.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/callback/ItemDragAndSwipeCallback.java new file mode 100644 index 0000000..c79b9b5 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/callback/ItemDragAndSwipeCallback.java @@ -0,0 +1,197 @@ +package com.xusangbo.basemoudle.weight.baseadapter.callback; + +import android.graphics.Canvas; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.view.View; + +import com.xusangbo.basemodule.R; +import com.xusangbo.basemoudle.weight.baseadapter.BaseItemDraggableAdapter; + + +/** + * Created by luoxw on 2016/6/20. + */ +public class ItemDragAndSwipeCallback extends ItemTouchHelper.Callback { + +// private static final String TAG = ItemDragAndSwipeCallback.class.getSimpleName(); + + BaseItemDraggableAdapter mAdapter; + + float mMoveThreshold = 0.1f; + float mSwipeThreshold = 0.7f; + + int mDragMoveFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; + int mSwipeMoveFlags = ItemTouchHelper.END; + + public ItemDragAndSwipeCallback(BaseItemDraggableAdapter adapter) { + mAdapter = adapter; + } + + @Override + public boolean isLongPressDragEnabled() { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return mAdapter.isItemSwipeEnable(); + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { + if (actionState == ItemTouchHelper.ACTION_STATE_DRAG + && !isViewCreateByAdapter(viewHolder)) { + mAdapter.onItemDragStart(viewHolder); + viewHolder.itemView.setTag(R.id.BaseQuickAdapter_dragging_support, true); + } else if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE + && !isViewCreateByAdapter(viewHolder)) { + mAdapter.onItemSwipeStart(viewHolder); + viewHolder.itemView.setTag(R.id.BaseQuickAdapter_swiping_support, true); + } + super.onSelectedChanged(viewHolder, actionState); + } + + @Override + public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + if (isViewCreateByAdapter(viewHolder)) { + return; + } + + if (viewHolder.itemView.getTag(R.id.BaseQuickAdapter_dragging_support) != null + && (Boolean)viewHolder.itemView.getTag(R.id.BaseQuickAdapter_dragging_support)) { + mAdapter.onItemDragEnd(viewHolder); + viewHolder.itemView.setTag(R.id.BaseQuickAdapter_dragging_support, false); + } + if (viewHolder.itemView.getTag(R.id.BaseQuickAdapter_swiping_support) != null + && (Boolean)viewHolder.itemView.getTag(R.id.BaseQuickAdapter_swiping_support)) { + mAdapter.onItemSwipeClear(viewHolder); + viewHolder.itemView.setTag(R.id.BaseQuickAdapter_swiping_support, false); + } + } + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + if (isViewCreateByAdapter(viewHolder)) { + return makeMovementFlags(0, 0); + } + + return makeMovementFlags(mDragMoveFlags, mSwipeMoveFlags); + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { + if (source.getItemViewType() != target.getItemViewType()) { + return false; + } else { + return true; + } + } + + @Override + public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder source, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) { + super.onMoved(recyclerView, source, fromPos, target, toPos, x, y); + mAdapter.onItemDragMoving(source, target); + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + if (!isViewCreateByAdapter(viewHolder)) { + mAdapter.onItemSwiped(viewHolder); + } + } + + @Override + public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) { + return mMoveThreshold; + } + + @Override + public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) { + return mSwipeThreshold; + } + + /** + * Set the fraction that the user should move the View to be considered as swiped. + * The fraction is calculated with respect to RecyclerView's bounds. + *

+ * Default value is .5f, which means, to swipe a View, user must move the View at least + * half of RecyclerView's width or height, depending on the swipe direction. + * + * @param swipeThreshold A float value that denotes the fraction of the View size. Default value + * is .8f . + */ + public void setSwipeThreshold(float swipeThreshold) { + mSwipeThreshold = swipeThreshold; + } + + + /** + * Set the fraction that the user should move the View to be considered as it is + * dragged. After a view is moved this amount, ItemTouchHelper starts checking for Views + * below it for a possible drop. + * + * @param moveThreshold A float value that denotes the fraction of the View size. Default value is + * .1f . + */ + public void setMoveThreshold(float moveThreshold) { + mMoveThreshold = moveThreshold; + } + + /** + *

Set the drag movement direction.

+ *

The value should be ItemTouchHelper.UP, ItemTouchHelper.DOWN, ItemTouchHelper.LEFT, ItemTouchHelper.RIGHT or their combination.

+ * You can combine them like ItemTouchHelper.UP | ItemTouchHelper.DOWN, it means that the item could only move up and down when dragged. + * @param dragMoveFlags the drag movement direction. Default value is ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT. + */ + public void setDragMoveFlags(int dragMoveFlags) { + mDragMoveFlags = dragMoveFlags; + } + + /** + *

Set the swipe movement direction.

+ *

The value should be ItemTouchHelper.START, ItemTouchHelper.END or their combination.

+ * You can combine them like ItemTouchHelper.START | ItemTouchHelper.END, it means that the item could swipe to both left or right. + * @param swipeMoveFlags the swipe movement direction. Default value is ItemTouchHelper.END. + */ + public void setSwipeMoveFlags(int swipeMoveFlags) { + mSwipeMoveFlags = swipeMoveFlags; + } + + @Override + public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, + float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + + if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE + && !isViewCreateByAdapter(viewHolder)) { + View itemView = viewHolder.itemView; + + c.save(); + if (dX > 0) { + c.clipRect(itemView.getLeft(), itemView.getTop(), + itemView.getLeft() + dX, itemView.getBottom()); + c.translate(itemView.getLeft(), itemView.getTop()); + } else { + c.clipRect(itemView.getRight() + dX, itemView.getTop(), + itemView.getRight(), itemView.getBottom()); + c.translate(itemView.getRight() + dX, itemView.getTop()); + } + + mAdapter.onItemSwiping(c, viewHolder, dX, dY, isCurrentlyActive); + c.restore(); + + } + } + + private boolean isViewCreateByAdapter(RecyclerView.ViewHolder viewHolder) { + int type = viewHolder.getItemViewType(); + if (type == mAdapter.HEADER_VIEW || type == mAdapter.LOADING_VIEW + || type == mAdapter.FOOTER_VIEW || type == mAdapter.EMPTY_VIEW) { + return true; + } + return false; + + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/AbstractExpandableItem.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/AbstractExpandableItem.java new file mode 100644 index 0000000..dbad092 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/AbstractExpandableItem.java @@ -0,0 +1,80 @@ +package com.xusangbo.basemoudle.weight.baseadapter.entity; + +import java.util.ArrayList; +import java.util.List; + +/** + *

A helper to implement expandable item.

+ *

if you don't want to extent a class, you can also implement the interface IExpandable

+ * Created by luoxw on 2016/8/9. + */ +public abstract class AbstractExpandableItem implements IExpandable { + protected boolean mExpandable = false; + protected List mSubItems; + + @Override + public boolean isExpanded() { + return mExpandable; + } + + @Override + public void setExpanded(boolean expanded) { + mExpandable = expanded; + } + + @Override + public List getSubItems() { + return mSubItems; + } + + public boolean hasSubItem() { + return mSubItems != null && mSubItems.size() > 0; + } + + public void setSubItems(List list) { + mSubItems = list; + } + + public T getSubItem(int position) { + if (hasSubItem() && position < mSubItems.size()) { + return mSubItems.get(position); + } else { + return null; + } + } + + public int getSubItemPosition(T subItem) { + return mSubItems != null ? mSubItems.indexOf(subItem) : -1; + } + + public void addSubItem(T subItem) { + if (mSubItems == null) { + mSubItems = new ArrayList<>(); + } + mSubItems.add(subItem); + } + + public void addSubItem(int position, T subItem) { + if (mSubItems != null && position >= 0 && position < mSubItems.size()) { + mSubItems.add(position, subItem); + } else { + addSubItem(subItem); + } + } + + public boolean contains(T subItem) { + return mSubItems != null && mSubItems.contains(subItem); + } + + public boolean removeSubItem(T subItem) { + return mSubItems != null && mSubItems.remove(subItem); + } + + public boolean removeSubItem(int position) { + if (mSubItems != null && position >= 0 && position < mSubItems.size()) { + mSubItems.remove(position); + return true; + } + return false; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/IExpandable.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/IExpandable.java new file mode 100644 index 0000000..690a63b --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/IExpandable.java @@ -0,0 +1,19 @@ +package com.xusangbo.basemoudle.weight.baseadapter.entity; + +import java.util.List; + +/** + * implement the interface if the item is expandable + * Created by luoxw on 2016/8/8. + */ +public interface IExpandable { + boolean isExpanded(); + void setExpanded(boolean expanded); + List getSubItems(); + + /** + * Get the level of this item. The level start from 0. + * If you don't care about the level, just return a negative. + */ + int getLevel(); +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/MultiItemEntity.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/MultiItemEntity.java new file mode 100644 index 0000000..004df4e --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/MultiItemEntity.java @@ -0,0 +1,10 @@ +package com.xusangbo.basemoudle.weight.baseadapter.entity; + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public interface MultiItemEntity { + + int getItemType(); + +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/SectionEntity.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/SectionEntity.java new file mode 100644 index 0000000..77b902d --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/entity/SectionEntity.java @@ -0,0 +1,22 @@ +package com.xusangbo.basemoudle.weight.baseadapter.entity; + +/** + * https://github.com/CymChad/BaseRecyclerViewAdapterHelper + */ +public abstract class SectionEntity { + public boolean isHeader; + public T t; + public String header; + + public SectionEntity(boolean isHeader, String header) { + this.isHeader = isHeader; + this.header = header; + this.t = null; + } + + public SectionEntity(T t) { + this.isHeader = false; + this.header = null; + this.t = t; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemChildClickListener.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemChildClickListener.java new file mode 100644 index 0000000..a001a92 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemChildClickListener.java @@ -0,0 +1,39 @@ +package com.xusangbo.basemoudle.weight.baseadapter.listener; + +import android.view.View; + +import com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter; + + +/** + * Created by AllenCoder on 2016/8/03. + * A convenience class to extend when you only want to OnItemChildClickListener for a subset + * of all the SimpleClickListener. This implements all methods in the + * {@link SimpleClickListener} + **/ + +public abstract class OnItemChildClickListener extends SimpleClickListener { + + @Override + public void onItemClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { + onSimpleItemChildClick(adapter, view, position); + } + + @Override + public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) { + + } + + public abstract void onSimpleItemChildClick(BaseQuickAdapter adapter, View view, int position); + +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemChildLongClickListener.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemChildLongClickListener.java new file mode 100644 index 0000000..c86e6c0 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemChildLongClickListener.java @@ -0,0 +1,37 @@ +package com.xusangbo.basemoudle.weight.baseadapter.listener; + +import android.view.View; + +import com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter; + + +/** + * Created by AllenCoder on 2016/8/03. + * A convenience class to extend when you only want to OnItemChildLongClickListener for a subset + * of all the SimpleClickListener. This implements all methods in the + * {@link SimpleClickListener} + **/ +public abstract class OnItemChildLongClickListener extends SimpleClickListener { + + + @Override + public void onItemClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) { + onSimpleItemChildLongClick(adapter,view,position); + } + public abstract void onSimpleItemChildLongClick(BaseQuickAdapter adapter, View view, int position); +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemClickListener.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemClickListener.java new file mode 100644 index 0000000..d3a65c8 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemClickListener.java @@ -0,0 +1,39 @@ +package com.xusangbo.basemoudle.weight.baseadapter.listener; + +import android.view.View; + +import com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter; + + +/** + * Created by AllenCoder on 2016/8/03. + * + * + * A convenience class to extend when you only want to OnItemClickListener for a subset + * of all the SimpleClickListener. This implements all methods in the + * {@link SimpleClickListener} + */ +public abstract class OnItemClickListener extends SimpleClickListener { + + + @Override + public void onItemClick(BaseQuickAdapter adapter, View view, int position) { + onSimpleItemClick(adapter,view,position); + } + + @Override + public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) { + + } + public abstract void onSimpleItemClick(BaseQuickAdapter adapter, View view, int position); +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemDragListener.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemDragListener.java new file mode 100644 index 0000000..c3821f7 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemDragListener.java @@ -0,0 +1,13 @@ +package com.xusangbo.basemoudle.weight.baseadapter.listener; + +import android.support.v7.widget.RecyclerView; + +/** + * Created by luoxw on 2016/6/20. + */ +public interface OnItemDragListener { + void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos); + void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to); + void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos); + +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemLongClickListener.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemLongClickListener.java new file mode 100644 index 0000000..4ef85b2 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemLongClickListener.java @@ -0,0 +1,36 @@ +package com.xusangbo.basemoudle.weight.baseadapter.listener; + +import android.view.View; + +import com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter; + + +/** + * create by: allen on 16/8/3. + */ + +public abstract class OnItemLongClickListener extends SimpleClickListener { + + + + + @Override + public void onItemClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) { + onSimpleItemLongClick( adapter, view, position); + } + + @Override + public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) { + + } + + @Override + public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) { + } + public abstract void onSimpleItemLongClick(BaseQuickAdapter adapter, View view, int position); +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemSwipeListener.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemSwipeListener.java new file mode 100644 index 0000000..782ea4d --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/OnItemSwipeListener.java @@ -0,0 +1,39 @@ +package com.xusangbo.basemoudle.weight.baseadapter.listener; + +import android.graphics.Canvas; +import android.support.v7.widget.RecyclerView; + +/** + * Created by luoxw on 2016/6/23. + */ +public interface OnItemSwipeListener { + + /** + * Called when the swipe action start. + */ + void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos); + + /** + * Called when the swipe action is over. + * If you change the view on the start, you should reset is here, no matter the item has swiped or not. + * @param pos If the view is swiped, pos will be negative. + */ + void clearView(RecyclerView.ViewHolder viewHolder, int pos); + /** + * Called when item is swiped, the view is going to be removed from the adapter. + */ + void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos); + + /** + * Draw on the empty edge when swipe moving + * @param canvas the empty edge's canvas + * @param viewHolder The ViewHolder which is being interacted by the User or it was + * interacted and simply animating to its original position + * @param dX The amount of horizontal displacement caused by user's action + * @param dY The amount of vertical displacement caused by user's action + * @param isCurrentlyActive True if this view is currently being controlled by the user or + * false it is simply animating back to its original state. + */ + void onItemSwipeMoving(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive); + +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/SimpleClickListener.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/SimpleClickListener.java new file mode 100644 index 0000000..7c06216 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/listener/SimpleClickListener.java @@ -0,0 +1,302 @@ +package com.xusangbo.basemoudle.weight.baseadapter.listener; + +import android.os.Build; +import android.support.v4.view.GestureDetectorCompat; +import android.support.v7.widget.RecyclerView; +import android.view.GestureDetector; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.View; + + +import com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter; +import com.xusangbo.basemoudle.weight.baseadapter.BaseViewHolder; + +import java.util.Set; + +import static com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter.EMPTY_VIEW; +import static com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter.FOOTER_VIEW; +import static com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter.HEADER_VIEW; +import static com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter.LOADING_VIEW; + +/** + * Created by AllenCoder on 2016/8/03. + *

+ * This can be useful for applications that wish to implement various forms of click and longclick and childView click + * manipulation of item views within the RecyclerView. SimpleClickListener may intercept + * a touch interaction already in progress even if the SimpleClickListener is already handling that + * gesture stream itself for the purposes of scrolling. + * + * @see RecyclerView.OnItemTouchListener + */ +public abstract class SimpleClickListener implements RecyclerView.OnItemTouchListener { + private GestureDetectorCompat mGestureDetector; + private RecyclerView recyclerView; + protected BaseQuickAdapter baseQuickAdapter; + public static String TAG = "SimpleClickListener"; + private boolean mIsPrepressed = false; + private boolean mIsShowPress = false; + private View mPressedView = null; + + @Override + public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { + if (recyclerView == null) { + this.recyclerView = rv; + this.baseQuickAdapter = (BaseQuickAdapter) recyclerView.getAdapter(); + mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new ItemTouchHelperGestureListener(recyclerView)); + }else if (recyclerView!=rv){ + this.recyclerView = rv; + this.baseQuickAdapter = (BaseQuickAdapter) recyclerView.getAdapter(); + mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new ItemTouchHelperGestureListener(recyclerView)); + } + if (!mGestureDetector.onTouchEvent(e) && e.getActionMasked() == MotionEvent.ACTION_UP && mIsShowPress) { + if (mPressedView!=null){ + BaseViewHolder vh = (BaseViewHolder) recyclerView.getChildViewHolder(mPressedView); + if (vh == null ||!isHeaderOrFooterView(vh.getItemViewType())) { + mPressedView.setPressed(false); + } + } + mIsShowPress = false; + mIsPrepressed = false; + } + return false; + } + + @Override + public void onTouchEvent(RecyclerView rv, MotionEvent e) { + mGestureDetector.onTouchEvent(e); + } + + @Override + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { + } + + private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener { + + private RecyclerView recyclerView; + + @Override + public boolean onDown(MotionEvent e) { + mIsPrepressed = true; + mPressedView = recyclerView.findChildViewUnder(e.getX(), e.getY()); + + super.onDown(e); + return false; + } + + @Override + public void onShowPress(MotionEvent e) { + if (mIsPrepressed && mPressedView != null) { +// mPressedView.setPressed(true); + mIsShowPress = true; + } + super.onShowPress(e); + } + + ItemTouchHelperGestureListener(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (mIsPrepressed && mPressedView != null) { + if (recyclerView.getScrollState()!=RecyclerView.SCROLL_STATE_IDLE){ + return false; + } + final View pressedView = mPressedView; + BaseViewHolder vh = (BaseViewHolder) recyclerView.getChildViewHolder(pressedView); + + if (isHeaderOrFooterPosition(vh.getLayoutPosition())) { + return false; + } + Set childClickViewIds = vh.getChildClickViewIds(); + Set nestViewIds = vh.getNestViews(); + if (childClickViewIds != null && childClickViewIds.size() > 0) { + for (Integer childClickViewId : childClickViewIds) { + View childView = pressedView.findViewById(childClickViewId); + if (childView != null) { + if (inRangeOfView(childView, e) && childView.isEnabled()) { + if (nestViewIds!=null&&nestViewIds.contains(childClickViewId)){ + return false; + } + setPressViewHotSpot(e, childView); + childView.setPressed(true); + onItemChildClick(baseQuickAdapter, childView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); + resetPressedView(childView); + return true; + } else { + childView.setPressed(false); + } + } + + } + setPressViewHotSpot(e,pressedView); + mPressedView.setPressed(true); + for (Integer childClickViewId : childClickViewIds) { + View childView = pressedView.findViewById(childClickViewId); + if (childView!=null){ + childView.setPressed(false); + } + } + onItemClick(baseQuickAdapter, pressedView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); + } else { + setPressViewHotSpot(e,pressedView); + mPressedView.setPressed(true); + if (childClickViewIds != null && childClickViewIds.size() > 0) { + for (Integer childClickViewId : childClickViewIds) { + View childView = pressedView.findViewById(childClickViewId); + if (childView!=null){ + childView.setPressed(false); + } + } + } + + onItemClick(baseQuickAdapter, pressedView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); + } + resetPressedView(pressedView); + + } + return true; + } + + private void resetPressedView(final View pressedView) { + if (pressedView!=null){ + pressedView.postDelayed(new Runnable() { + @Override + public void run() { + if (pressedView!=null){ + pressedView.setPressed(false); + } + + } + },50); + } + + mIsPrepressed = false; + mPressedView = null; + } + + @Override + public void onLongPress(MotionEvent e) { + boolean isChildLongClick =false; + if (recyclerView.getScrollState()!=RecyclerView.SCROLL_STATE_IDLE){ + return ; + } + if (mIsPrepressed && mPressedView != null) { + mPressedView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + BaseViewHolder vh = (BaseViewHolder) recyclerView.getChildViewHolder(mPressedView); + if (!isHeaderOrFooterPosition(vh.getLayoutPosition())) { + Set longClickViewIds = vh.getItemChildLongClickViewIds(); + Set nestViewIds = vh.getNestViews(); + if (longClickViewIds != null && longClickViewIds.size() > 0) { + for (Integer longClickViewId : longClickViewIds) { + View childView = mPressedView.findViewById(longClickViewId); + if (inRangeOfView(childView, e) && childView.isEnabled()) { + if (nestViewIds!=null&&nestViewIds.contains(longClickViewId)){ + isChildLongClick=true; + break; + } + setPressViewHotSpot(e, childView); + onItemChildLongClick(baseQuickAdapter, childView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); + childView.setPressed(true); + mIsShowPress = true; + isChildLongClick = true; + break; + } + } + } + if (!isChildLongClick){ + + onItemLongClick(baseQuickAdapter, mPressedView, vh.getLayoutPosition() - baseQuickAdapter.getHeaderLayoutCount()); + setPressViewHotSpot(e,mPressedView); + mPressedView.setPressed(true); + if (longClickViewIds != null) { + for (Integer longClickViewId : longClickViewIds) { + View childView = mPressedView.findViewById(longClickViewId); + childView.setPressed(false); + } + } + mIsShowPress = true; + } + + } + + } + } + + + } + + private void setPressViewHotSpot(final MotionEvent e,final View mPressedView) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + /** + * when click Outside the region ,mPressedView is null + */ + if (mPressedView !=null && mPressedView.getBackground() != null) { + mPressedView.getBackground().setHotspot(e.getRawX(), e.getY()-mPressedView.getY()); + } + } + } + + /** + * Callback method to be invoked when an item in this AdapterView has + * been clicked. + * + * @param view The view within the AdapterView that was clicked (this + * will be a view provided by the adapter) + * @param position The position of the view in the adapter. + */ + public abstract void onItemClick(BaseQuickAdapter adapter, View view, int position); + + /** + * callback method to be invoked when an item in this view has been + * click and held + * + * @param view The view whihin the AbsListView that was clicked + * @param position The position of the view int the adapter + * @return true if the callback consumed the long click ,false otherwise + */ + public abstract void onItemLongClick(BaseQuickAdapter adapter, View view, int position); + + public abstract void onItemChildClick(BaseQuickAdapter adapter, View view, int position); + + public abstract void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position); + + public boolean inRangeOfView(View view, MotionEvent ev) { + int[] location = new int[2]; + if (view==null||!view.isShown()){ + return false; + } + view.getLocationOnScreen(location); + int x = location[0]; + int y = location[1]; + if (ev.getRawX() < x + || ev.getRawX() > (x + view.getWidth()) + || ev.getRawY() < y + || ev.getRawY() > (y + view.getHeight())) { + return false; + } + return true; + } + + private boolean isHeaderOrFooterPosition(int position) { + /** + * have a headview and EMPTY_VIEW FOOTER_VIEW LOADING_VIEW + */ + if (baseQuickAdapter==null){ + if (recyclerView!=null){ + baseQuickAdapter= (BaseQuickAdapter) recyclerView.getAdapter(); + }else { + return false; + } + } + int type = baseQuickAdapter.getItemViewType(position); + return (type == EMPTY_VIEW || type == HEADER_VIEW || type == FOOTER_VIEW || type == LOADING_VIEW); + } + private boolean isHeaderOrFooterView(int type) { + + return (type == EMPTY_VIEW || type == HEADER_VIEW || type == FOOTER_VIEW || type == LOADING_VIEW); + } +} + + diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/loadmore/LoadMoreView.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/loadmore/LoadMoreView.java new file mode 100644 index 0000000..ff2cbee --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/loadmore/LoadMoreView.java @@ -0,0 +1,117 @@ +package com.xusangbo.basemoudle.weight.baseadapter.loadmore; + +import android.support.annotation.IdRes; +import android.support.annotation.LayoutRes; + +import com.xusangbo.basemoudle.weight.baseadapter.BaseQuickAdapter; +import com.xusangbo.basemoudle.weight.baseadapter.BaseViewHolder; + + +/** + * Created by BlingBling on 2016/11/11. + */ + +public abstract class LoadMoreView { + + public static final int STATUS_DEFAULT = 1; + public static final int STATUS_LOADING = 2; + public static final int STATUS_FAIL = 3; + public static final int STATUS_END = 4; + + private int mLoadMoreStatus = STATUS_DEFAULT; + private boolean mLoadMoreEndGone = false; + + public void setLoadMoreStatus(int loadMoreStatus) { + this.mLoadMoreStatus = loadMoreStatus; + } + + public int getLoadMoreStatus() { + return mLoadMoreStatus; + } + + public void convert(BaseViewHolder holder) { + switch (mLoadMoreStatus) { + case STATUS_LOADING: + visibleLoading(holder, true); + visibleLoadFail(holder, false); + visibleLoadEnd(holder, false); + break; + case STATUS_FAIL: + visibleLoading(holder, false); + visibleLoadFail(holder, true); + visibleLoadEnd(holder, false); + break; + case STATUS_END: + visibleLoading(holder, false); + visibleLoadFail(holder, false); + visibleLoadEnd(holder, true); + break; + case STATUS_DEFAULT: + visibleLoading(holder, false); + visibleLoadFail(holder, false); + visibleLoadEnd(holder, false); + break; + } + } + + private void visibleLoading(BaseViewHolder holder, boolean visible) { + holder.setVisible(getLoadingViewId(), visible); + } + + private void visibleLoadFail(BaseViewHolder holder, boolean visible) { + holder.setVisible(getLoadFailViewId(), visible); + } + + private void visibleLoadEnd(BaseViewHolder holder, boolean visible) { + final int loadEndViewId=getLoadEndViewId(); + if (loadEndViewId != 0) { + holder.setVisible(loadEndViewId, visible); + } + } + + public final void setLoadMoreEndGone(boolean loadMoreEndGone) { + this.mLoadMoreEndGone = loadMoreEndGone; + } + + public final boolean isLoadEndMoreGone(){ + if(getLoadEndViewId()==0){ + return true; + } + return mLoadMoreEndGone;} + + /** + * No more data is hidden + * @return true for no more data hidden load more + * @deprecated Use {@link BaseQuickAdapter#loadMoreEnd(boolean)} instead. + */ + @Deprecated + public boolean isLoadEndGone(){return mLoadMoreEndGone;} + + /** + * load more layout + * + * @return + */ + public abstract @LayoutRes int getLayoutId(); + + /** + * loading view + * + * @return + */ + protected abstract @IdRes int getLoadingViewId(); + + /** + * load fail view + * + * @return + */ + protected abstract @IdRes int getLoadFailViewId(); + + /** + * load end view, you can return 0 + * + * @return + */ + protected abstract @IdRes int getLoadEndViewId(); +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/loadmore/SimpleLoadMoreView.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/loadmore/SimpleLoadMoreView.java new file mode 100644 index 0000000..19f569c --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/loadmore/SimpleLoadMoreView.java @@ -0,0 +1,27 @@ +package com.xusangbo.basemoudle.weight.baseadapter.loadmore; + + +import com.xusangbo.basemodule.R; + +/** + * Created by BlingBling on 2016/10/11. + */ + +public final class SimpleLoadMoreView extends LoadMoreView { + + @Override public int getLayoutId() { + return R.layout.quick_view_load_more; + } + + @Override protected int getLoadingViewId() { + return R.id.load_more_loading_view; + } + + @Override protected int getLoadFailViewId() { + return R.id.load_more_load_fail_view; + } + + @Override protected int getLoadEndViewId() { + return R.id.load_more_load_end_view; + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/util/MultiTypeDelegate.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/util/MultiTypeDelegate.java new file mode 100644 index 0000000..39b49b8 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/util/MultiTypeDelegate.java @@ -0,0 +1,90 @@ +package com.xusangbo.basemoudle.weight.baseadapter.util; + +import android.support.annotation.LayoutRes; +import android.util.SparseIntArray; + +import java.util.List; + +/** + * help you to achieve multi type easily + *

+ * Created by tysheng + * Date: 2017/4/6 08:41. + * Email: tyshengsx@gmail.com + *

+ * + * more information: https://github.com/CymChad/BaseRecyclerViewAdapterHelper/issues/968 + */ + +public abstract class MultiTypeDelegate { + + private static final int DEFAULT_VIEW_TYPE = -0xff; + private SparseIntArray layouts; + private boolean autoMode, selfMode; + + public MultiTypeDelegate(SparseIntArray layouts) { + this.layouts = layouts; + } + + public MultiTypeDelegate() { + } + + public final int getDefItemViewType(List data, int position) { + T item = data.get(position); + return item != null ? getItemType(item) : DEFAULT_VIEW_TYPE; + } + + /** + * get the item type from specific entity. + * + * @param t entity + * @return item type + */ + protected abstract int getItemType(T t); + + public final int getLayoutId(int viewType) { + return this.layouts.get(viewType); + } + + private void addItemType(int type, @LayoutRes int layoutResId) { + if (this.layouts == null) { + this.layouts = new SparseIntArray(); + } + this.layouts.put(type, layoutResId); + } + + /** + * auto increase type vale, start from 0. + * + * @param layoutResIds layout id arrays + * @return MultiTypeDelegate + */ + public MultiTypeDelegate registerItemTypeAutoIncrease(@LayoutRes int... layoutResIds) { + autoMode = true; + checkMode(selfMode); + for (int i = 0; i < layoutResIds.length; i++) { + addItemType(i, layoutResIds[i]); + } + return this; + } + + /** + * set your own type one by one. + * + * @param type type value + * @param layoutResId layout id + * @return MultiTypeDelegate + */ + public MultiTypeDelegate registerItemType(int type, @LayoutRes int layoutResId) { + selfMode = true; + checkMode(autoMode); + addItemType(type, layoutResId); + return this; + } + + private void checkMode(boolean mode) { + if (mode) { + throw new RuntimeException("Don't mess two register mode"); + } + } +} diff --git a/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/util/TouchEventUtil.java b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/util/TouchEventUtil.java new file mode 100644 index 0000000..597f350 --- /dev/null +++ b/Basemodule/src/main/java/com/xusangbo/basemoudle/weight/baseadapter/util/TouchEventUtil.java @@ -0,0 +1,29 @@ +package com.xusangbo.basemoudle.weight.baseadapter.util; + +import android.view.MotionEvent; + +public class TouchEventUtil { + + public static String getTouchAction(int actionId) { + String actionName = "Unknow:id=" + actionId; + switch (actionId) { + case MotionEvent.ACTION_DOWN: + actionName = "ACTION_DOWN"; + break; + case MotionEvent.ACTION_MOVE: + actionName = "ACTION_MOVE"; + break; + case MotionEvent.ACTION_UP: + actionName = "ACTION_UP"; + break; + case MotionEvent.ACTION_CANCEL: + actionName = "ACTION_CANCEL"; + break; + case MotionEvent.ACTION_OUTSIDE: + actionName = "ACTION_OUTSIDE"; + break; + } + return actionName; + } + +} diff --git a/Basemodule/src/main/res/layout/quick_view_load_more.xml b/Basemodule/src/main/res/layout/quick_view_load_more.xml new file mode 100644 index 0000000..08b3bc8 --- /dev/null +++ b/Basemodule/src/main/res/layout/quick_view_load_more.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Basemodule/src/main/res/values/attrs.xml b/Basemodule/src/main/res/values/attrs.xml index 17a49ba..26aae89 100644 --- a/Basemodule/src/main/res/values/attrs.xml +++ b/Basemodule/src/main/res/values/attrs.xml @@ -26,40 +26,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Basemodule/src/main/res/values/dimens.xml b/Basemodule/src/main/res/values/dimens.xml index d3e9038..6d270b4 100644 --- a/Basemodule/src/main/res/values/dimens.xml +++ b/Basemodule/src/main/res/values/dimens.xml @@ -7,9 +7,12 @@ 24dp 12dp - 24dp - 12dp - 48dp - 24dp - 12dp + 4dp + 10dp + 40dp + 72dp + + 12sp + 14sp + 16sp \ No newline at end of file diff --git a/Basemodule/src/main/res/values/ids.xml b/Basemodule/src/main/res/values/ids.xml index cafab0c..79c50f2 100644 --- a/Basemodule/src/main/res/values/ids.xml +++ b/Basemodule/src/main/res/values/ids.xml @@ -7,4 +7,9 @@ + + + + + \ No newline at end of file diff --git a/Basemodule/src/main/res/values/strings.xml b/Basemodule/src/main/res/values/strings.xml index 3709900..d463389 100644 --- a/Basemodule/src/main/res/values/strings.xml +++ b/Basemodule/src/main/res/values/strings.xml @@ -4,5 +4,6 @@ 请稍后... 重新尝试 网络不可用,请检查你的网络 - + 加载失败,请点我重试 + 没有更多数据 diff --git a/app/app.iml b/app/app.iml index 4ed0554..0c7a94a 100644 --- a/app/app.iml +++ b/app/app.iml @@ -77,40 +77,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index d5125f8..78b4934 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,4 +28,7 @@ dependencies { compile 'com.android.support:appcompat-v7:25.2.0' compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha4' testCompile 'junit:junit:4.12' + compile 'com.squareup.retrofit2:retrofit:2.0.0' + compile 'com.squareup.okhttp3:logging-interceptor:3.1.2' + compile project(path: ':Basemodule') } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8393311..3f356b3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="com.basemoudle.sample"> + + + + \ No newline at end of file diff --git a/app/src/main/java/com/basemoudle/sample/MainActivity.java b/app/src/main/java/com/basemoudle/sample/MainActivity.java index 1482716..4950676 100644 --- a/app/src/main/java/com/basemoudle/sample/MainActivity.java +++ b/app/src/main/java/com/basemoudle/sample/MainActivity.java @@ -2,12 +2,50 @@ import android.support.v7.app.AppCompatActivity; import android.os.Bundle; +import android.view.View; +import android.widget.Button; -public class MainActivity extends AppCompatActivity { +import com.basemoudle.sample.activity.MVCActivity; +import com.basemoudle.sample.activity.MVPActivity; +import com.xusangbo.basemoudle.base.BaseActivity; + +public class MainActivity extends BaseActivity implements View.OnClickListener { + private Button bt_mvc; + private Button bt_mvp; + + + @Override + protected void getBundleExtras(Bundle extras) { + + } + + @Override + public int getLayoutId() { + return R.layout.activity_main; + } + + @Override + public void initPresenter() { + + } + + @Override + public void initView() { + bt_mvc = (Button) findViewById(R.id.bt_mvc); + bt_mvp = (Button) findViewById(R.id.bt_mvp); + bt_mvc.setOnClickListener(this); + bt_mvp.setOnClickListener(this); + } @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); + public void onClick(View view) { + switch (view.getId()) { + case R.id.bt_mvc: + readyGo(MVCActivity.class); + break; + case R.id.bt_mvp: + readyGo(MVPActivity.class); + break; + } } } diff --git a/app/src/main/java/com/basemoudle/sample/activity/MVCActivity.java b/app/src/main/java/com/basemoudle/sample/activity/MVCActivity.java new file mode 100644 index 0000000..77af846 --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/activity/MVCActivity.java @@ -0,0 +1,32 @@ +package com.basemoudle.sample.activity; + +import android.os.Bundle; + +import com.basemoudle.sample.R; +import com.xusangbo.basemoudle.base.BaseActivity; + +/** + * Created by hasee on 2017/5/14. + */ + +public class MVCActivity extends BaseActivity { + @Override + protected void getBundleExtras(Bundle extras) { + + } + + @Override + public int getLayoutId() { + return R.layout.activity_main; + } + + @Override + public void initPresenter() { + + } + + @Override + public void initView() { + + } +} diff --git a/app/src/main/java/com/basemoudle/sample/activity/MVPActivity.java b/app/src/main/java/com/basemoudle/sample/activity/MVPActivity.java new file mode 100644 index 0000000..aeee494 --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/activity/MVPActivity.java @@ -0,0 +1,61 @@ +package com.basemoudle.sample.activity; + +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +import com.basemoudle.sample.R; +import com.basemoudle.sample.contract.MVPContract; +import com.basemoudle.sample.model.MVPModel; +import com.basemoudle.sample.persenter.MVPPersenter; +import com.xusangbo.basemoudle.base.BaseActivity; + +/** + * Created by hasee on 2017/5/14. + */ + +public class MVPActivity extends BaseActivity implements MVPContract.View { + private Button bt_demo; + + @Override + protected void getBundleExtras(Bundle extras) { + + } + + @Override + public int getLayoutId() { + return R.layout.activity_main; + } + + @Override + public void initPresenter() { + mPresenter.setVM(this, mModel); + } + + @Override + public void initView() { + bt_demo = (Button) findViewById(R.id.bt_demo); + bt_demo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mPresenter.postData(); + + } + }); + } + + @Override + public void showLoading(String title) { + + } + + @Override + public void stopLoading() { + + } + + @Override + public void showErrorTip(String msg) { + + } +} diff --git a/app/src/main/java/com/basemoudle/sample/api/Api.java b/app/src/main/java/com/basemoudle/sample/api/Api.java new file mode 100644 index 0000000..b0cf2f8 --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/api/Api.java @@ -0,0 +1,185 @@ +package com.basemoudle.sample.api; + + +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.xusangbo.basemoudle.base.BaseApplication; +import com.xusangbo.basemoudle.utils.NetWorkUtils; + +import java.io.File; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import okhttp3.Cache; +import okhttp3.CacheControl; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * des:retorfit api + * Created by xsf + * on 2016.06.15:47 + */ +public class Api { + //读超时长,单位:毫秒 + public static final int READ_TIME_OUT = 7676; + //连接时长,单位:毫秒 + public static final int CONNECT_TIME_OUT = 7676; + public Retrofit retrofit; + public ApiService movieService; + + private static SparseArray sRetrofitManager = new SparseArray<>(HostType.TYPE_COUNT); + + /*************************缓存设置*********************/ +/* + 1. noCache 不使用缓存,全部走网络 + + 2. noStore 不使用缓存,也不存储缓存 + + 3. onlyIfCached 只使用缓存 + + 4. maxAge 设置最大失效时间,失效则不使用 需要服务器配合 + + 5. maxStale 设置最大失效时间,失效则不使用 需要服务器配合 感觉这两个类似 还没怎么弄清楚,清楚的同学欢迎留言 + + 6. minFresh 设置有效时间,依旧如上 + + 7. FORCE_NETWORK 只走网络 + + 8. FORCE_CACHE 只走缓存*/ + + /** + * 设缓存有效期为两天 + */ + private static final long CACHE_STALE_SEC = 60 * 60 * 24 * 2; + /** + * 查询缓存的Cache-Control设置,为if-only-cache时只查询缓存而不会请求服务器,max-stale可以配合设置缓存失效时间 + * max-stale 指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可接收超出超时期指定值之内的响应消息。 + */ + private static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC; + /** + * 查询网络的Cache-Control设置,头部Cache-Control设为max-age=0 + * (假如请求了服务器并在a时刻返回响应结果,则在max-age规定的秒数内,浏览器将不会发送对应的请求到服务器,数据由缓存直接返回)时则不会使用缓存而请求服务器 + */ + private static final String CACHE_CONTROL_AGE = "max-age=0"; + + + //构造方法私有 + private Api(int hostType) { + //开启Log + HttpLoggingInterceptor logInterceptor=new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { + @Override + public void log(String message) { + Log.e("XUSANGBO_OkHttpClient","OkHttpMessage:"+message); + } + }); + logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + //缓存 + File cacheFile = new File(BaseApplication.getAppContext().getCacheDir(), "cache"); + Cache cache = new Cache(cacheFile, 1024 * 1024 * 100); //100Mb + //增加头部信息 + Interceptor headerInterceptor = new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + Request build = chain.request().newBuilder() + .addHeader("Content-Type", "application/json") + .build(); + return chain.proceed(build); + } + }; + + OkHttpClient okHttpClient = new OkHttpClient.Builder() + .readTimeout(READ_TIME_OUT, TimeUnit.MILLISECONDS) + .connectTimeout(CONNECT_TIME_OUT, TimeUnit.MILLISECONDS) + .addInterceptor(mRewriteCacheControlInterceptor) + .addNetworkInterceptor(mRewriteCacheControlInterceptor) + .addInterceptor(headerInterceptor) + .addInterceptor(logInterceptor) + .cache(cache) + .build(); + + Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").serializeNulls().create(); + retrofit = new Retrofit.Builder() + .client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create(gson)) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .baseUrl(ApiConstants.BASEURL) + .build(); + movieService = retrofit.create(ApiService.class); + } + + + /** + * @param hostType NETEASE_NEWS_VIDEO:1 (新闻,视频),GANK_GIRL_PHOTO:2(图片新闻); + * EWS_DETAIL_HTML_PHOTO:3新闻详情html图片) + */ + public static ApiService getDefault(int hostType) { + Api retrofitManager = sRetrofitManager.get(hostType); + if (retrofitManager == null) { + retrofitManager = new Api(hostType); + sRetrofitManager.put(hostType, retrofitManager); + } + return retrofitManager.movieService; + } + + public static ApiService getDefault() { + Api retrofitManager = sRetrofitManager.get(0); + + if (retrofitManager == null) { + retrofitManager = new Api(0); + sRetrofitManager.put(0, retrofitManager); + } + return retrofitManager.movieService; + + } + + /** + * 根据网络状况获取缓存的策略 + */ + @NonNull + public static String getCacheControl() { + return NetWorkUtils.isNetConnected(BaseApplication.getAppContext()) ? CACHE_CONTROL_AGE : CACHE_CONTROL_CACHE; + } + + /** + * 云端响应头拦截器,用来配置缓存策略 + * Dangerous interceptor that rewrites the server's cache-control header. + */ + private final Interceptor mRewriteCacheControlInterceptor = new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + String cacheControl = request.cacheControl().toString(); + if (!NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) { + request = request.newBuilder() + .cacheControl(TextUtils.isEmpty(cacheControl) ? CacheControl.FORCE_NETWORK : CacheControl.FORCE_CACHE) + .build(); + } + Response originalResponse = chain.proceed(request); + if (NetWorkUtils.isNetConnected(BaseApplication.getAppContext())) { + //有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置 + + return originalResponse.newBuilder() + .header("Cache-Control", cacheControl) + .removeHeader("Pragma") + .build(); + } else { + return originalResponse.newBuilder() + .header("Cache-Control", "public, only-if-cached, max-stale=" + CACHE_STALE_SEC) + .removeHeader("Pragma") + .build(); + } + } + }; +} \ No newline at end of file diff --git a/app/src/main/java/com/basemoudle/sample/api/ApiConstants.java b/app/src/main/java/com/basemoudle/sample/api/ApiConstants.java new file mode 100644 index 0000000..48f96cd --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/api/ApiConstants.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 咖枯 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.basemoudle.sample.api; + +public class ApiConstants { +public static final String BASEURL="http://zhuoji.zhanyiwangluo.com/"; + + + +// /** +// * 新闻id获取类型 +// * +// * @param id 新闻id +// * @return 新闻类型 +// */ +// public static String getType(String id) { +// switch (id) { +// case HEADLINE_ID: +// return HEADLINE_TYPE; +// case HOUSE_ID: +// return HOUSE_TYPE; +// default: +// break; +// } +// return OTHER_TYPE; +// } + + /** + * 获取对应的host + * + * @param hostType host类型 + * @return host + */ + public static String getHost(int hostType) { + String host; + switch (hostType) { + case HostType.HOME_NEW_LIST: + host = ""; + break; + case HostType.PICTURE_NEW_LIST: + host = ""; + break; + + default: + host = ""; + break; + } + return host; + } +} diff --git a/app/src/main/java/com/basemoudle/sample/api/ApiService.java b/app/src/main/java/com/basemoudle/sample/api/ApiService.java new file mode 100644 index 0000000..6d5031c --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/api/ApiService.java @@ -0,0 +1,18 @@ +package com.basemoudle.sample.api; + + + +import com.basemoudle.sample.bean.User; +import com.xusangbo.basemoudle.base.BaseRespose; + +import retrofit2.http.POST; +import rx.Observable; + +/** + * Created by boxu on 2017/4/4. + */ + +public interface ApiService { + @POST("Home/User/login") + Observable> postData(); +} diff --git a/app/src/main/java/com/basemoudle/sample/api/HostType.java b/app/src/main/java/com/basemoudle/sample/api/HostType.java new file mode 100644 index 0000000..24a3212 --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/api/HostType.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 咖枯 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.basemoudle.sample.api; + +public class HostType { + + /** + * 多少种Host类型 + */ + public static final int TYPE_COUNT = 2; + + /** + * 首页类型host + */ + public static final int HOME_NEW_LIST = 1; + + /** + * 图片上传类型host + */ + public static final int PICTURE_NEW_LIST = 2; + + + +} diff --git a/app/src/main/java/com/basemoudle/sample/app/AppApplication.java b/app/src/main/java/com/basemoudle/sample/app/AppApplication.java new file mode 100644 index 0000000..55b2ce8 --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/app/AppApplication.java @@ -0,0 +1,18 @@ +package com.basemoudle.sample.app; + +import com.xusangbo.basemodule.BuildConfig; +import com.xusangbo.basemoudle.base.BaseApplication; +import com.xusangbo.basemoudle.utils.LogUtils; + +/** + * Created by boxu on 2017/4/4. + */ + +public class AppApplication extends BaseApplication { + @Override + public void onCreate() { + super.onCreate(); + //初始化logger + LogUtils.logInit(BuildConfig.LOG_DEBUG); + } +} diff --git a/app/src/main/java/com/basemoudle/sample/bean/User.java b/app/src/main/java/com/basemoudle/sample/bean/User.java new file mode 100644 index 0000000..d2b037c --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/bean/User.java @@ -0,0 +1,8 @@ +package com.basemoudle.sample.bean; + +/** + * Created by hasee on 2017/5/14. + */ + +public class User { +} diff --git a/app/src/main/java/com/basemoudle/sample/contract/MVPContract.java b/app/src/main/java/com/basemoudle/sample/contract/MVPContract.java new file mode 100644 index 0000000..d136bcc --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/contract/MVPContract.java @@ -0,0 +1,30 @@ +package com.basemoudle.sample.contract; + +import com.basemoudle.sample.bean.User; +import com.xusangbo.basemoudle.base.BaseModel; +import com.xusangbo.basemoudle.base.BasePresenter; +import com.xusangbo.basemoudle.base.BaseRespose; +import com.xusangbo.basemoudle.base.BaseView; + +import rx.Observable; + +/** + * Created by boxu on 2017/4/24. + */ + +public interface MVPContract { + + interface Model extends BaseModel { + + Observable> postData(); + } + + interface View extends BaseView { + + } + + abstract static class Presenter extends BasePresenter { + public abstract void postData(); + + } +} diff --git a/app/src/main/java/com/basemoudle/sample/model/MVPModel.java b/app/src/main/java/com/basemoudle/sample/model/MVPModel.java new file mode 100644 index 0000000..a70f366 --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/model/MVPModel.java @@ -0,0 +1,20 @@ +package com.basemoudle.sample.model; + +import com.basemoudle.sample.api.Api; +import com.basemoudle.sample.bean.User; +import com.basemoudle.sample.contract.MVPContract; +import com.xusangbo.basemoudle.base.BaseRespose; +import com.xusangbo.basemoudle.baserx.RxSchedulers; + +import rx.Observable; + +/** + * Created by hasee on 2017/5/14. + */ + +public class MVPModel implements MVPContract.Model { + @Override + public Observable> postData() { + return Api.getDefault().postData().compose(RxSchedulers.>io_main()); + } +} diff --git a/app/src/main/java/com/basemoudle/sample/persenter/MVPPersenter.java b/app/src/main/java/com/basemoudle/sample/persenter/MVPPersenter.java new file mode 100644 index 0000000..1f4bd72 --- /dev/null +++ b/app/src/main/java/com/basemoudle/sample/persenter/MVPPersenter.java @@ -0,0 +1,27 @@ +package com.basemoudle.sample.persenter; + +import com.basemoudle.sample.bean.User; +import com.basemoudle.sample.contract.MVPContract; +import com.xusangbo.basemoudle.base.BaseRespose; +import com.xusangbo.basemoudle.baserx.RxSubscriber; + +/** + * Created by hasee on 2017/5/14. + */ + +public class MVPPersenter extends MVPContract.Presenter { + @Override + public void postData() { + mModel.postData().subscribe(new RxSubscriber>(mContext, false) { + @Override + protected void _onNext(BaseRespose userBaseRespose) { +//处理请求返回数据 + } + + @Override + protected void _onError(String message) { + + } + }); + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 81b1969..df0d072 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,15 +1,20 @@ - + android:orientation="vertical" +> - - - +