parent
d51ff9e71d
commit
077a84239f
63 changed files with 5788 additions and 429 deletions
@ -0,0 +1,21 @@ |
|||||||
|
package com.project.survey.activity.approval |
||||||
|
|
||||||
|
import com.project.survey.activity.base.BaseBindingActivity |
||||||
|
import com.project.survey.databinding.ActivityApprovalBinding |
||||||
|
|
||||||
|
/** |
||||||
|
* 待处理,已处理,已发起 |
||||||
|
*/ |
||||||
|
class ApprovalActivity : BaseBindingActivity<ActivityApprovalBinding>() { |
||||||
|
override fun getBinding(): ActivityApprovalBinding { |
||||||
|
return ActivityApprovalBinding.inflate(layoutInflater) |
||||||
|
} |
||||||
|
|
||||||
|
override fun initView() { |
||||||
|
TODO("Not yet implemented") |
||||||
|
} |
||||||
|
|
||||||
|
override fun initData() { |
||||||
|
TODO("Not yet implemented") |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
package com.project.survey.activity.project |
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
import com.bingce.ui.TabEntity |
||||||
|
import com.flyco.tablayout.listener.CustomTabEntity |
||||||
|
import com.project.survey.R |
||||||
|
import com.project.survey.activity.base.BaseBindingActivity |
||||||
|
import com.project.survey.databinding.ActivityProjectListBinding |
||||||
|
|
||||||
|
class ProjectListActivity : BaseBindingActivity<ActivityProjectListBinding>() { |
||||||
|
override fun getBinding(): ActivityProjectListBinding { |
||||||
|
return ActivityProjectListBinding.inflate(layoutInflater) |
||||||
|
} |
||||||
|
|
||||||
|
override fun initView() { |
||||||
|
initTabLayout() |
||||||
|
} |
||||||
|
|
||||||
|
private fun initTabLayout() { |
||||||
|
val mTabEntities = ArrayList<CustomTabEntity>() |
||||||
|
mTabEntities.add( |
||||||
|
TabEntity( |
||||||
|
"最近打开", |
||||||
|
R.drawable.ic_project_recently, |
||||||
|
R.drawable.ic_project_recently |
||||||
|
) |
||||||
|
) |
||||||
|
mTabEntities.add( |
||||||
|
TabEntity( |
||||||
|
"全部", |
||||||
|
R.drawable.ic_project_all, |
||||||
|
R.drawable.ic_project_all |
||||||
|
) |
||||||
|
) |
||||||
|
val fragmentList = ArrayList<Fragment>() |
||||||
|
fragmentList.add(ProjectListFragment.newInstance(ProjectListFragment.TYPE_RECENTLY)) |
||||||
|
fragmentList.add(ProjectListFragment.newInstance(ProjectListFragment.TYPE_ALL)) |
||||||
|
|
||||||
|
mBinding.tabLayout.setTabData(mTabEntities, this, R.id.container, fragmentList) |
||||||
|
} |
||||||
|
|
||||||
|
override fun initData() { |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
package com.project.survey.activity.project |
||||||
|
|
||||||
|
import android.view.LayoutInflater |
||||||
|
import android.view.ViewGroup |
||||||
|
import androidx.core.os.bundleOf |
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
import com.project.survey.adapter.ProjectListAdapter |
||||||
|
import com.project.survey.databinding.FragmentProjectListBinding |
||||||
|
import com.project.survey.fragment.base.BaseFragmentBinding |
||||||
|
import com.project.survey.model.ProjectBean |
||||||
|
import com.project.survey.widget.decoration.HorDividerDecoration |
||||||
|
|
||||||
|
class ProjectListFragment : BaseFragmentBinding<FragmentProjectListBinding>() { |
||||||
|
|
||||||
|
private val adapter by lazy { ProjectListAdapter(requireContext()) } |
||||||
|
|
||||||
|
companion object { |
||||||
|
const val TYPE_RECENTLY = "1" |
||||||
|
const val TYPE_ALL = "2" |
||||||
|
const val KEY_TYPE = "KEY_TYPE" |
||||||
|
|
||||||
|
fun newInstance(type: String): Fragment { |
||||||
|
val fragment = ProjectListFragment() |
||||||
|
fragment.arguments = bundleOf( |
||||||
|
KEY_TYPE to type |
||||||
|
) |
||||||
|
return fragment |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun getViewBinding( |
||||||
|
inflater: LayoutInflater, |
||||||
|
container: ViewGroup? |
||||||
|
): FragmentProjectListBinding { |
||||||
|
return FragmentProjectListBinding.inflate(inflater, container, false) |
||||||
|
} |
||||||
|
|
||||||
|
override fun initView() { |
||||||
|
initAdapter() |
||||||
|
} |
||||||
|
|
||||||
|
override fun initData() { |
||||||
|
val type = getArgumentString(KEY_TYPE) |
||||||
|
|
||||||
|
val num = if (type == TYPE_RECENTLY) { |
||||||
|
3 |
||||||
|
} else { |
||||||
|
6 |
||||||
|
} |
||||||
|
|
||||||
|
val dataList = mutableListOf<ProjectBean>() |
||||||
|
for (i in 0 until num) { |
||||||
|
dataList.add(ProjectBean()) |
||||||
|
} |
||||||
|
|
||||||
|
adapter.refreshData(dataList) |
||||||
|
} |
||||||
|
|
||||||
|
private fun initAdapter() { |
||||||
|
mBinding.recyclerView.addItemDecoration(HorDividerDecoration(requireContext())) |
||||||
|
adapter.setOnItemClickListener { |
||||||
|
|
||||||
|
} |
||||||
|
mBinding.recyclerView.setAdapter(adapter) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
package com.project.survey.adapter; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
|
||||||
|
import com.project.survey.adapter.base.BaseAdapter; |
||||||
|
import com.project.survey.adapter.viewholder.ProjectListViewHolder; |
||||||
|
import com.project.survey.databinding.ItemProjectListBinding; |
||||||
|
import com.project.survey.model.ProjectBean; |
||||||
|
|
||||||
|
|
||||||
|
public class ProjectListAdapter extends BaseAdapter<ProjectListViewHolder, ProjectBean> { |
||||||
|
|
||||||
|
public ProjectListAdapter(Context context) { |
||||||
|
super(context); |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public ProjectListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |
||||||
|
return new ProjectListViewHolder(ItemProjectListBinding.inflate(getInflater(), parent, false)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onBindViewHolderDo(ProjectListViewHolder holder, int position) { |
||||||
|
ProjectBean bean = mDataList.get(position); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,87 @@ |
|||||||
|
package com.project.survey.adapter.base; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.view.ContextMenu; |
||||||
|
import android.view.LayoutInflater; |
||||||
|
import android.view.MenuItem; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/10/3. |
||||||
|
*/ |
||||||
|
public abstract class BaseAdapter<VH extends RecyclerView.ViewHolder, T> extends RecyclerView.Adapter<VH> { |
||||||
|
private IItemClickListener<T> mItemClickListener; |
||||||
|
protected IAdapterContextMenu<T> adapterContextMenu; |
||||||
|
|
||||||
|
protected List<T> mDataList; |
||||||
|
protected Context mContext; |
||||||
|
|
||||||
|
private final LayoutInflater mInflater; |
||||||
|
|
||||||
|
public BaseAdapter(Context context) { |
||||||
|
this.mContext = context; |
||||||
|
this.mInflater = LayoutInflater.from(context); |
||||||
|
} |
||||||
|
|
||||||
|
public LayoutInflater getInflater() { |
||||||
|
return mInflater; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public int getItemCount() { |
||||||
|
return mDataList == null ? 0 : mDataList.size(); |
||||||
|
} |
||||||
|
|
||||||
|
public T getBean(int position) { |
||||||
|
return mDataList.get(position); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onBindViewHolder(@NonNull VH holder, int position) { |
||||||
|
holder.itemView.setOnClickListener(v -> { |
||||||
|
if (mItemClickListener != null) { |
||||||
|
mItemClickListener.clickItem(mDataList.get(holder.getBindingAdapterPosition())); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
holder.itemView.setOnCreateContextMenuListener((menu, v, menuInfo) -> |
||||||
|
createMenu(menu, mDataList.get(holder.getBindingAdapterPosition()))); |
||||||
|
|
||||||
|
onBindViewHolderDo(holder, position); |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract void onBindViewHolderDo(VH holder, int position); |
||||||
|
|
||||||
|
|
||||||
|
protected void createMenu(ContextMenu menu, T bean) { |
||||||
|
if (adapterContextMenu == null) return; |
||||||
|
menu.clear(); |
||||||
|
for (int index = 0; index < adapterContextMenu.menuItemSize(); index++) { |
||||||
|
menu.add(0, index, 0, adapterContextMenu.menuItemName(index)); |
||||||
|
MenuItem menuItem = menu.getItem(index); |
||||||
|
if (menuItem != null) { |
||||||
|
menuItem.setOnMenuItemClickListener(item -> |
||||||
|
adapterContextMenu.onMenuItemClick(bean, item)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void setAdapterContextMenu(IAdapterContextMenu<T> adapterContextMenu) { |
||||||
|
this.adapterContextMenu = adapterContextMenu; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOnItemClickListener(IItemClickListener<T> mItemClickListener) { |
||||||
|
this.mItemClickListener = mItemClickListener; |
||||||
|
} |
||||||
|
|
||||||
|
public void refreshData(List<T> dataList) { |
||||||
|
this.mDataList = dataList; |
||||||
|
notifyDataSetChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package com.project.survey.adapter.base; |
||||||
|
|
||||||
|
import android.view.MenuItem; |
||||||
|
|
||||||
|
import androidx.annotation.StringRes; |
||||||
|
|
||||||
|
public interface IAdapterContextMenu<T> { |
||||||
|
int menuItemSize(); |
||||||
|
|
||||||
|
@StringRes |
||||||
|
int menuItemName(int index); |
||||||
|
|
||||||
|
boolean onMenuItemClick(T item, MenuItem menuItem); |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
package com.project.survey.adapter.base; |
||||||
|
|
||||||
|
public interface IItemClickListener<T> { |
||||||
|
void clickItem(T t); |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
package com.project.survey.adapter.viewholder; |
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
import com.project.survey.databinding.ItemProjectListBinding; |
||||||
|
|
||||||
|
|
||||||
|
public class ProjectListViewHolder extends RecyclerView.ViewHolder { |
||||||
|
public final ItemProjectListBinding mBinding; |
||||||
|
|
||||||
|
public ProjectListViewHolder(ItemProjectListBinding binding) { |
||||||
|
super(binding.getRoot()); |
||||||
|
mBinding = binding; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
package com.project.survey.model |
||||||
|
|
||||||
|
class ProjectBean { |
||||||
|
} |
@ -0,0 +1,383 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.decoration; |
||||||
|
|
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
import androidx.annotation.ColorInt; |
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.recyclerview.widget.GridLayoutManager; |
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager; |
||||||
|
|
||||||
|
import com.project.survey.widget.swiperecyclerview.widget.ColorDrawer; |
||||||
|
import com.project.survey.widget.swiperecyclerview.widget.Drawer; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/8/14. |
||||||
|
*/ |
||||||
|
public class DefaultItemDecoration extends RecyclerView.ItemDecoration { |
||||||
|
|
||||||
|
private final int mWidth; |
||||||
|
private final int mHeight; |
||||||
|
private final Drawer mDrawer; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param color divider line color. |
||||||
|
*/ |
||||||
|
public DefaultItemDecoration(@ColorInt int color) { |
||||||
|
this(color, 4, 4); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param color line color. |
||||||
|
* @param width line width. |
||||||
|
* @param height line height. |
||||||
|
*/ |
||||||
|
public DefaultItemDecoration(@ColorInt int color, int width, int height) { |
||||||
|
this.mWidth = Math.round(width / 2F); |
||||||
|
this.mHeight = Math.round(height / 2F); |
||||||
|
this.mDrawer = new ColorDrawer(color, mWidth, mHeight); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, |
||||||
|
@NonNull RecyclerView.State state) { |
||||||
|
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); |
||||||
|
if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
int orientation = getOrientation(layoutManager); |
||||||
|
int position = parent.getChildLayoutPosition(view); |
||||||
|
int spanCount = getSpanCount(layoutManager); |
||||||
|
int childCount = layoutManager.getItemCount(); |
||||||
|
|
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
offsetVertical(outRect, position, spanCount, childCount); |
||||||
|
} else { |
||||||
|
offsetHorizontal(outRect, position, spanCount, childCount); |
||||||
|
} |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
outRect.set(mWidth, mHeight, mWidth, mHeight); // |-|-
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void offsetHorizontal(Rect outRect, int position, int spanCount, int childCount) { |
||||||
|
boolean firstRaw = isFirstRaw(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean lastRaw = isLastRaw(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean firstColumn = isFirstColumn(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean lastColumn = isLastColumn(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
|
||||||
|
if (spanCount == 1) { |
||||||
|
if (firstColumn && lastColumn) { // xxxx
|
||||||
|
outRect.set(0, 0, 0, 0); |
||||||
|
} else if (firstColumn) { // xx|x
|
||||||
|
outRect.set(0, 0, mWidth, 0); |
||||||
|
} else if (lastColumn) { // |xxx
|
||||||
|
outRect.set(mWidth, 0, 0, 0); |
||||||
|
} else { // |x|x
|
||||||
|
outRect.set(mWidth, 0, mWidth, 0); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (firstColumn && firstRaw) { // xx|-
|
||||||
|
outRect.set(0, 0, mWidth, mHeight); |
||||||
|
} else if (firstColumn && lastRaw) { // x-|x
|
||||||
|
outRect.set(0, mHeight, mWidth, 0); |
||||||
|
} else if (lastColumn && firstRaw) { // |xx-
|
||||||
|
outRect.set(mWidth, 0, 0, mHeight); |
||||||
|
} else if (lastColumn && lastRaw) { // |-xx
|
||||||
|
outRect.set(mWidth, mHeight, 0, 0); |
||||||
|
} else if (firstColumn) { // x-|-
|
||||||
|
outRect.set(0, mHeight, mWidth, mHeight); |
||||||
|
} else if (lastColumn) { // |-x-
|
||||||
|
outRect.set(mWidth, mHeight, 0, mHeight); |
||||||
|
} else if (firstRaw) { // |x|-
|
||||||
|
outRect.set(mWidth, 0, mWidth, mHeight); |
||||||
|
} else if (lastRaw) { // |-|x
|
||||||
|
outRect.set(mWidth, mHeight, mWidth, 0); |
||||||
|
} else { // |-|-
|
||||||
|
outRect.set(mWidth, mHeight, mWidth, mHeight); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void offsetVertical(Rect outRect, int position, int spanCount, int childCount) { |
||||||
|
boolean firstRaw = isFirstRaw(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean lastRaw = isLastRaw(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean firstColumn = isFirstColumn(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean lastColumn = isLastColumn(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
|
||||||
|
if (spanCount == 1) { |
||||||
|
if (firstRaw && lastRaw) { // xxxx
|
||||||
|
outRect.set(0, 0, 0, 0); |
||||||
|
} else if (firstRaw) { // xxx-
|
||||||
|
outRect.set(0, 0, 0, mHeight); |
||||||
|
} else if (lastRaw) { // x-xx
|
||||||
|
outRect.set(0, mHeight, 0, 0); |
||||||
|
} else { // x-x-
|
||||||
|
outRect.set(0, mHeight, 0, mHeight); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (firstRaw && firstColumn) { // xx|-
|
||||||
|
outRect.set(0, 0, mWidth, mHeight); |
||||||
|
} else if (firstRaw && lastColumn) { // |xx-
|
||||||
|
outRect.set(mWidth, 0, 0, mHeight); |
||||||
|
} else if (lastRaw && firstColumn) { // x-|x
|
||||||
|
outRect.set(0, mHeight, mWidth, 0); |
||||||
|
} else if (lastRaw && lastColumn) { // |-xx
|
||||||
|
outRect.set(mWidth, mHeight, 0, 0); |
||||||
|
} else if (firstRaw) { // |x|-
|
||||||
|
outRect.set(mWidth, 0, mWidth, mHeight); |
||||||
|
} else if (lastRaw) { // |-|x
|
||||||
|
outRect.set(mWidth, mHeight, mWidth, 0); |
||||||
|
} else if (firstColumn) { // x-|-
|
||||||
|
outRect.set(0, mHeight, mWidth, mHeight); |
||||||
|
} else if (lastColumn) { // |-x-
|
||||||
|
outRect.set(mWidth, mHeight, 0, mHeight); |
||||||
|
} else { // |-|-
|
||||||
|
outRect.set(mWidth, mHeight, mWidth, mHeight); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int getOrientation(RecyclerView.LayoutManager layoutManager) { |
||||||
|
if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
return ((LinearLayoutManager)layoutManager).getOrientation(); |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
return ((StaggeredGridLayoutManager)layoutManager).getOrientation(); |
||||||
|
} |
||||||
|
return RecyclerView.VERTICAL; |
||||||
|
} |
||||||
|
|
||||||
|
private int getSpanCount(RecyclerView.LayoutManager layoutManager) { |
||||||
|
if (layoutManager instanceof GridLayoutManager) { |
||||||
|
return ((GridLayoutManager)layoutManager).getSpanCount(); |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
return ((StaggeredGridLayoutManager)layoutManager).getSpanCount(); |
||||||
|
} |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isFirstRaw(int orientation, int position, int columnCount, int childCount) { |
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
return position < columnCount; |
||||||
|
} else { |
||||||
|
if (columnCount == 1) return true; |
||||||
|
return position % columnCount == 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isLastRaw(int orientation, int position, int columnCount, int childCount) { |
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
if (columnCount == 1) { |
||||||
|
return position + 1 == childCount; |
||||||
|
} else { |
||||||
|
int lastRawItemCount = childCount % columnCount; |
||||||
|
int rawCount = (childCount - lastRawItemCount) / columnCount + (lastRawItemCount > 0 ? 1 : 0); |
||||||
|
|
||||||
|
int rawPositionJudge = (position + 1) % columnCount; |
||||||
|
if (rawPositionJudge == 0) { |
||||||
|
int positionRaw = (position + 1) / columnCount; |
||||||
|
return rawCount == positionRaw; |
||||||
|
} else { |
||||||
|
int rawPosition = (position + 1 - rawPositionJudge) / columnCount + 1; |
||||||
|
return rawCount == rawPosition; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (columnCount == 1) return true; |
||||||
|
return (position + 1) % columnCount == 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isFirstColumn(int orientation, int position, int columnCount, int childCount) { |
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
if (columnCount == 1) return true; |
||||||
|
return position % columnCount == 0; |
||||||
|
} else { |
||||||
|
return position < columnCount; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isLastColumn(int orientation, int position, int columnCount, int childCount) { |
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
if (columnCount == 1) return true; |
||||||
|
return (position + 1) % columnCount == 0; |
||||||
|
} else { |
||||||
|
if (columnCount == 1) { |
||||||
|
return position + 1 == childCount; |
||||||
|
} else { |
||||||
|
int lastRawItemCount = childCount % columnCount; |
||||||
|
int rawCount = (childCount - lastRawItemCount) / columnCount + (lastRawItemCount > 0 ? 1 : 0); |
||||||
|
|
||||||
|
int rawPositionJudge = (position + 1) % columnCount; |
||||||
|
if (rawPositionJudge == 0) { |
||||||
|
int positionRaw = (position + 1) / columnCount; |
||||||
|
return rawCount == positionRaw; |
||||||
|
} else { |
||||||
|
int rawPosition = (position + 1 - rawPositionJudge) / columnCount + 1; |
||||||
|
return rawCount == rawPosition; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { |
||||||
|
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); |
||||||
|
assert layoutManager != null; |
||||||
|
int orientation = getOrientation(layoutManager); |
||||||
|
int spanCount = getSpanCount(layoutManager); |
||||||
|
int childCount = layoutManager.getChildCount(); |
||||||
|
|
||||||
|
if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
canvas.save(); |
||||||
|
for (int i = 0; i < childCount; i++) { |
||||||
|
View view = layoutManager.getChildAt(i); |
||||||
|
assert view != null; |
||||||
|
int position = parent.getChildLayoutPosition(view); |
||||||
|
|
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
drawVertical(canvas, view, position, spanCount, childCount); |
||||||
|
} else { |
||||||
|
drawHorizontal(canvas, view, position, spanCount, childCount); |
||||||
|
} |
||||||
|
} |
||||||
|
canvas.restore(); |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
canvas.save(); |
||||||
|
for (int i = 0; i < childCount; i++) { |
||||||
|
View view = layoutManager.getChildAt(i); |
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
canvas.restore(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void drawHorizontal(Canvas canvas, View view, int position, int spanCount, int childCount) { |
||||||
|
boolean firstRaw = isFirstRaw(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean lastRaw = isLastRaw(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean firstColumn = isFirstColumn(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean lastColumn = isLastColumn(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
|
||||||
|
if (spanCount == 1) { |
||||||
|
if (firstRaw && lastColumn) { // xxxx
|
||||||
|
// Nothing.
|
||||||
|
} else if (firstColumn) { // xx|x
|
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else if (lastColumn) { // |xxx
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
} else { // |x|x
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (firstColumn && firstRaw) { // xx|-
|
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (firstColumn && lastRaw) { // x-|x
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else if (lastColumn && firstRaw) { // |xx-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastColumn && lastRaw) { // |-xx
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
} else if (firstColumn) { // x-|-
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastColumn) { // |-x-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (firstRaw) { // |x|-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastRaw) { // |-|x
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else { // |-|-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void drawVertical(Canvas canvas, View view, int position, int spanCount, int childCount) { |
||||||
|
boolean firstRaw = isFirstRaw(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean lastRaw = isLastRaw(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean firstColumn = isFirstColumn(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean lastColumn = isLastColumn(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
|
||||||
|
if (spanCount == 1) { |
||||||
|
if (firstRaw && lastRaw) { // xxxx
|
||||||
|
// Nothing.
|
||||||
|
} else if (firstRaw) { // xxx-
|
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastRaw) { // x-xx
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
} else { // x-x-
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (firstRaw && firstColumn) { // xx|-
|
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (firstRaw && lastColumn) { // |xx-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastRaw && firstColumn) { // x-|x
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else if (lastRaw && lastColumn) { // |-xx
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
} else if (firstRaw) { // |x|-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastRaw) { // |-|x
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else if (firstColumn) { // x-|-
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastColumn) { // |-x-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else { // |-|-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package com.project.survey.widget.decoration |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import androidx.core.content.ContextCompat |
||||||
|
import com.project.survey.R |
||||||
|
|
||||||
|
class HorDividerDecoration(context: Context) : DefaultItemDecoration( |
||||||
|
ContextCompat.getColor(context, R.color.hor_line), |
||||||
|
1, 1 |
||||||
|
) |
@ -1,323 +0,0 @@ |
|||||||
package com.project.survey.widget.edittext; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.content.res.TypedArray; |
|
||||||
import android.graphics.Typeface; |
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
import android.os.Parcel; |
|
||||||
import android.os.Parcelable; |
|
||||||
import android.text.Editable; |
|
||||||
import android.text.TextWatcher; |
|
||||||
import android.text.method.PasswordTransformationMethod; |
|
||||||
import android.util.AttributeSet; |
|
||||||
import android.view.MotionEvent; |
|
||||||
|
|
||||||
import androidx.appcompat.widget.AppCompatEditText; |
|
||||||
|
|
||||||
import com.project.survey.R; |
|
||||||
import com.project.survey.util.DensityUtils; |
|
||||||
import com.project.survey.util.ResUtils; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* 支持显示密码的输入框 |
|
||||||
* |
|
||||||
* @author xuexiang |
|
||||||
* @since 2019/1/14 下午10:08 |
|
||||||
*/ |
|
||||||
public class PasswordEditText extends AppCompatEditText { |
|
||||||
/** |
|
||||||
* 增大点击区域 |
|
||||||
*/ |
|
||||||
private int mExtraClickArea; |
|
||||||
|
|
||||||
private final static int ALPHA_ICON_ENABLED = (int) (255 * 0.54f); |
|
||||||
private final static int ALPHA_ICON_DISABLED = (int) (255 * 0.38f); |
|
||||||
|
|
||||||
private Drawable mShowPwDrawable; |
|
||||||
private Drawable mHidePwDrawable; |
|
||||||
private boolean mPasswordVisible; |
|
||||||
private boolean mShowingIcon; |
|
||||||
private boolean mSetErrorCalled; |
|
||||||
private boolean mHoverShowsPw; |
|
||||||
private boolean mHandlingHoverEvent; |
|
||||||
private PasswordTransformationMethod mTransformationMethod; |
|
||||||
|
|
||||||
public PasswordEditText(Context context) { |
|
||||||
this(context, null); |
|
||||||
} |
|
||||||
|
|
||||||
public PasswordEditText(Context context, AttributeSet attrs) { |
|
||||||
this(context, attrs, R.attr.PasswordEditTextStyle); |
|
||||||
} |
|
||||||
|
|
||||||
public PasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) { |
|
||||||
super(context, attrs, defStyleAttr); |
|
||||||
initAttrs(context, attrs, defStyleAttr); |
|
||||||
} |
|
||||||
|
|
||||||
public void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) { |
|
||||||
mExtraClickArea = DensityUtils.dp2px(context, 20); |
|
||||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PasswordEditText, defStyleAttr, 0); |
|
||||||
boolean useNonMonospaceFont; |
|
||||||
boolean enableIconAlpha; |
|
||||||
try { |
|
||||||
mShowPwDrawable = ResUtils.getDrawableAttrRes(getContext(), typedArray, R.styleable.PasswordEditText_pet_iconShow); |
|
||||||
if (mShowPwDrawable == null) { |
|
||||||
mShowPwDrawable = ResUtils.getVectorDrawable(getContext(), R.drawable.pet_icon_visibility_24dp); |
|
||||||
} |
|
||||||
mHidePwDrawable = ResUtils.getDrawableAttrRes(getContext(), typedArray, R.styleable.PasswordEditText_pet_iconHide); |
|
||||||
if (mHidePwDrawable == null) { |
|
||||||
mHidePwDrawable = ResUtils.getVectorDrawable(getContext(), R.drawable.pet_icon_visibility_off_24dp); |
|
||||||
} |
|
||||||
mHoverShowsPw = typedArray.getBoolean(R.styleable.PasswordEditText_pet_hoverShowsPw, false); |
|
||||||
useNonMonospaceFont = typedArray.getBoolean(R.styleable.PasswordEditText_pet_nonMonospaceFont, false); |
|
||||||
enableIconAlpha = typedArray.getBoolean(R.styleable.PasswordEditText_pet_enableIconAlpha, true); |
|
||||||
boolean isAsteriskStyle = typedArray.getBoolean(R.styleable.PasswordEditText_pet_isAsteriskStyle, false); |
|
||||||
if (isAsteriskStyle) { |
|
||||||
mTransformationMethod = AsteriskPasswordTransformationMethod.getInstance(); |
|
||||||
} else { |
|
||||||
mTransformationMethod = PasswordTransformationMethod.getInstance(); |
|
||||||
} |
|
||||||
} finally { |
|
||||||
typedArray.recycle(); |
|
||||||
} |
|
||||||
|
|
||||||
if (enableIconAlpha) { |
|
||||||
mHidePwDrawable.setAlpha(ALPHA_ICON_ENABLED); |
|
||||||
mShowPwDrawable.setAlpha(ALPHA_ICON_DISABLED); |
|
||||||
} |
|
||||||
|
|
||||||
if (useNonMonospaceFont) { |
|
||||||
setTypeface(Typeface.DEFAULT); |
|
||||||
} |
|
||||||
|
|
||||||
addTextChangedListener(new TextWatcher() { |
|
||||||
@Override |
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) { |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onTextChanged(CharSequence seq, int start, int before, int count) { |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void afterTextChanged(Editable s) { |
|
||||||
if (s.length() > 0) { |
|
||||||
if (mSetErrorCalled) { |
|
||||||
setCompoundDrawablesRelative(null, null, null, null); |
|
||||||
mSetErrorCalled = false; |
|
||||||
showPasswordVisibilityIndicator(true); |
|
||||||
} |
|
||||||
if (!mShowingIcon) { |
|
||||||
showPasswordVisibilityIndicator(true); |
|
||||||
} |
|
||||||
} else { |
|
||||||
// hides the indicator if no text inside text field
|
|
||||||
mPasswordVisible = false; |
|
||||||
handlePasswordInputVisibility(); |
|
||||||
showPasswordVisibilityIndicator(false); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
handlePasswordInputVisibility(); |
|
||||||
} |
|
||||||
|
|
||||||
public PasswordEditText setExtraClickAreaSize(int extraClickArea) { |
|
||||||
mExtraClickArea = extraClickArea; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 设置密码输入框的样式 |
|
||||||
* |
|
||||||
* @param transformationMethod |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public PasswordEditText setPasswordTransformationMethod(PasswordTransformationMethod transformationMethod) { |
|
||||||
mTransformationMethod = transformationMethod; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 设置密码输入框的样式 |
|
||||||
* |
|
||||||
* @param isAsteriskStyle |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public PasswordEditText setIsAsteriskStyle(boolean isAsteriskStyle) { |
|
||||||
if (isAsteriskStyle) { |
|
||||||
mTransformationMethod = AsteriskPasswordTransformationMethod.getInstance(); |
|
||||||
} else { |
|
||||||
mTransformationMethod = PasswordTransformationMethod.getInstance(); |
|
||||||
} |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
private boolean isRtl() { |
|
||||||
return getLayoutDirection() == LAYOUT_DIRECTION_RTL; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public Parcelable onSaveInstanceState() { |
|
||||||
Parcelable superState = super.onSaveInstanceState(); |
|
||||||
return new SavedState(superState, mShowingIcon, mPasswordVisible); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onRestoreInstanceState(Parcelable state) { |
|
||||||
SavedState savedState = (SavedState) state; |
|
||||||
super.onRestoreInstanceState(savedState.getSuperState()); |
|
||||||
mShowingIcon = savedState.isShowingIcon(); |
|
||||||
mPasswordVisible = savedState.isPasswordVisible(); |
|
||||||
handlePasswordInputVisibility(); |
|
||||||
showPasswordVisibilityIndicator(mShowingIcon); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setError(CharSequence error) { |
|
||||||
super.setError(error); |
|
||||||
mSetErrorCalled = true; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setError(CharSequence error, Drawable icon) { |
|
||||||
super.setError(error, icon); |
|
||||||
mSetErrorCalled = true; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean onTouchEvent(MotionEvent event) { |
|
||||||
if (!mShowingIcon) { |
|
||||||
return super.onTouchEvent(event); |
|
||||||
} else { |
|
||||||
boolean touchable = isTouchable(event); |
|
||||||
switch (event.getAction()) { |
|
||||||
case MotionEvent.ACTION_DOWN: |
|
||||||
if (mHoverShowsPw) { |
|
||||||
if (touchable) { |
|
||||||
togglePasswordIconVisibility(); |
|
||||||
// prevent keyboard from coming up
|
|
||||||
event.setAction(MotionEvent.ACTION_CANCEL); |
|
||||||
mHandlingHoverEvent = true; |
|
||||||
} |
|
||||||
} |
|
||||||
break; |
|
||||||
case MotionEvent.ACTION_UP: |
|
||||||
if (mHandlingHoverEvent || touchable) { |
|
||||||
togglePasswordIconVisibility(); |
|
||||||
// prevent keyboard from coming up
|
|
||||||
event.setAction(MotionEvent.ACTION_CANCEL); |
|
||||||
mHandlingHoverEvent = false; |
|
||||||
} |
|
||||||
break; |
|
||||||
default: |
|
||||||
break; |
|
||||||
} |
|
||||||
return super.onTouchEvent(event); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private boolean isTouchable(MotionEvent event) { |
|
||||||
boolean touchable; |
|
||||||
if (isRtl()) { |
|
||||||
touchable = event.getX() > getPaddingLeft() - mExtraClickArea && event.getX() < getPaddingLeft() + mShowPwDrawable.getIntrinsicWidth() + mExtraClickArea; |
|
||||||
} else { |
|
||||||
touchable = event.getX() > getWidth() - getPaddingRight() - mShowPwDrawable.getIntrinsicWidth() - mExtraClickArea && event.getX() < getWidth() - getPaddingRight() + mExtraClickArea; |
|
||||||
} |
|
||||||
return touchable; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private void showPasswordVisibilityIndicator(boolean shouldShowIcon) { |
|
||||||
if (shouldShowIcon) { |
|
||||||
Drawable drawable = mPasswordVisible ? mShowPwDrawable : mHidePwDrawable; |
|
||||||
mShowingIcon = true; |
|
||||||
setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, drawable, null); |
|
||||||
} else { |
|
||||||
// reset drawable
|
|
||||||
setCompoundDrawablesRelative(null, null, null, null); |
|
||||||
mShowingIcon = false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This method toggles the visibility of the icon and takes care of switching the input type |
|
||||||
* of the view to be able to see the password afterwards. |
|
||||||
* <p> |
|
||||||
* This method may only be called if there is an icon visible |
|
||||||
*/ |
|
||||||
private void togglePasswordIconVisibility() { |
|
||||||
mPasswordVisible = !mPasswordVisible; |
|
||||||
handlePasswordInputVisibility(); |
|
||||||
showPasswordVisibilityIndicator(true); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* This method is called when restoring the state (e.g. on orientation change) |
|
||||||
*/ |
|
||||||
private void handlePasswordInputVisibility() { |
|
||||||
int selectionStart = getSelectionStart(); |
|
||||||
int selectionEnd = getSelectionEnd(); |
|
||||||
if (mPasswordVisible) { |
|
||||||
setTransformationMethod(null); |
|
||||||
} else { |
|
||||||
setTransformationMethod(mTransformationMethod); |
|
||||||
} |
|
||||||
setSelection(selectionStart, selectionEnd); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Convenience class to save / restore the state of icon. |
|
||||||
*/ |
|
||||||
protected static class SavedState extends BaseSavedState { |
|
||||||
|
|
||||||
private final boolean mShowingIcon; |
|
||||||
private final boolean mPasswordVisible; |
|
||||||
|
|
||||||
private SavedState(Parcelable superState, boolean sI, boolean pV) { |
|
||||||
super(superState); |
|
||||||
mShowingIcon = sI; |
|
||||||
mPasswordVisible = pV; |
|
||||||
} |
|
||||||
|
|
||||||
private SavedState(Parcel in) { |
|
||||||
super(in); |
|
||||||
mShowingIcon = in.readByte() != 0; |
|
||||||
mPasswordVisible = in.readByte() != 0; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isShowingIcon() { |
|
||||||
return mShowingIcon; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isPasswordVisible() { |
|
||||||
return mPasswordVisible; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void writeToParcel(Parcel destination, int flags) { |
|
||||||
super.writeToParcel(destination, flags); |
|
||||||
destination.writeByte((byte) (mShowingIcon ? 1 : 0)); |
|
||||||
destination.writeByte((byte) (mPasswordVisible ? 1 : 0)); |
|
||||||
} |
|
||||||
|
|
||||||
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { |
|
||||||
|
|
||||||
@Override |
|
||||||
public SavedState createFromParcel(Parcel in) { |
|
||||||
return new SavedState(in); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public SavedState[] newArray(int size) { |
|
||||||
return new SavedState[size]; |
|
||||||
} |
|
||||||
|
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,57 @@ |
|||||||
|
package com.project.survey.widget.edittext; |
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.text.method.HideReturnsTransformationMethod; |
||||||
|
import android.text.method.PasswordTransformationMethod; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.LayoutInflater; |
||||||
|
import android.view.View; |
||||||
|
import android.widget.EditText; |
||||||
|
import android.widget.ImageView; |
||||||
|
import android.widget.RelativeLayout; |
||||||
|
|
||||||
|
import com.project.survey.R; |
||||||
|
|
||||||
|
public class PasswordView extends RelativeLayout { |
||||||
|
|
||||||
|
private EditText etPwd; |
||||||
|
private ImageView ivPwdShowHide; |
||||||
|
|
||||||
|
public PasswordView(Context context, AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
init(context); |
||||||
|
} |
||||||
|
|
||||||
|
public PasswordView(Context context) { |
||||||
|
super(context); |
||||||
|
init(context); |
||||||
|
} |
||||||
|
|
||||||
|
private void init(Context context) { |
||||||
|
LayoutInflater.from(context).inflate(R.layout.view_password, this, true); |
||||||
|
etPwd = findViewById(R.id.etPwd); |
||||||
|
View pwdShowHide = findViewById(R.id.pwdShowHide); |
||||||
|
ivPwdShowHide = findViewById(R.id.ivPwdShowHide); |
||||||
|
|
||||||
|
pwdShowHide.setOnClickListener(v -> { |
||||||
|
ivPwdShowHide.setSelected(!ivPwdShowHide.isSelected()); |
||||||
|
|
||||||
|
if (ivPwdShowHide.isSelected()) { |
||||||
|
etPwd.setTransformationMethod(HideReturnsTransformationMethod.getInstance()); |
||||||
|
} else { |
||||||
|
etPwd.setTransformationMethod(PasswordTransformationMethod.getInstance()); |
||||||
|
} |
||||||
|
etPwd.setSelection(etPwd.getText().length()); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public String getText() { |
||||||
|
return etPwd.getText().toString().trim(); |
||||||
|
} |
||||||
|
|
||||||
|
public void clearEtPwdText() { |
||||||
|
etPwd.setText(""); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,351 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
|
||||||
|
import static com.project.survey.widget.swiperecyclerview.SwipeRecyclerView.LEFT_DIRECTION; |
||||||
|
import static com.project.survey.widget.swiperecyclerview.SwipeRecyclerView.RIGHT_DIRECTION; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.view.LayoutInflater; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.collection.SparseArrayCompat; |
||||||
|
import androidx.recyclerview.widget.GridLayoutManager; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager; |
||||||
|
|
||||||
|
|
||||||
|
import com.project.survey.R; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/7/20. |
||||||
|
*/ |
||||||
|
class AdapterWrapper extends RecyclerView.Adapter<RecyclerView.ViewHolder> { |
||||||
|
|
||||||
|
private static final int BASE_ITEM_TYPE_HEADER = 100000; |
||||||
|
private static final int BASE_ITEM_TYPE_FOOTER = 200000; |
||||||
|
|
||||||
|
private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>(); |
||||||
|
private SparseArrayCompat<View> mFootViews = new SparseArrayCompat<>(); |
||||||
|
|
||||||
|
private RecyclerView.Adapter mAdapter; |
||||||
|
private LayoutInflater mInflater; |
||||||
|
|
||||||
|
private SwipeMenuCreator mSwipeMenuCreator; |
||||||
|
private OnItemMenuClickListener mOnItemMenuClickListener; |
||||||
|
private OnItemClickListener mOnItemClickListener; |
||||||
|
private OnItemLongClickListener mOnItemLongClickListener; |
||||||
|
|
||||||
|
AdapterWrapper(Context context, RecyclerView.Adapter adapter) { |
||||||
|
this.mInflater = LayoutInflater.from(context); |
||||||
|
this.mAdapter = adapter; |
||||||
|
} |
||||||
|
|
||||||
|
public RecyclerView.Adapter getOriginAdapter() { |
||||||
|
return mAdapter; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set to create menu listener. |
||||||
|
* |
||||||
|
* @param swipeMenuCreator listener. |
||||||
|
*/ |
||||||
|
void setSwipeMenuCreator(SwipeMenuCreator swipeMenuCreator) { |
||||||
|
this.mSwipeMenuCreator = swipeMenuCreator; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set to click menu listener. |
||||||
|
* |
||||||
|
* @param onItemMenuClickListener listener. |
||||||
|
*/ |
||||||
|
void setOnItemMenuClickListener(OnItemMenuClickListener onItemMenuClickListener) { |
||||||
|
this.mOnItemMenuClickListener = onItemMenuClickListener; |
||||||
|
} |
||||||
|
|
||||||
|
void setOnItemClickListener(OnItemClickListener onItemClickListener) { |
||||||
|
this.mOnItemClickListener = onItemClickListener; |
||||||
|
} |
||||||
|
|
||||||
|
void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) { |
||||||
|
this.mOnItemLongClickListener = onItemLongClickListener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getItemCount() { |
||||||
|
return getHeaderCount() + getContentItemCount() + getFooterCount(); |
||||||
|
} |
||||||
|
|
||||||
|
private int getContentItemCount() { |
||||||
|
return mAdapter.getItemCount(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getItemViewType(int position) { |
||||||
|
if (isHeader(position)) { |
||||||
|
return mHeaderViews.keyAt(position); |
||||||
|
} else if (isFooter(position)) { |
||||||
|
return mFootViews.keyAt(position - getHeaderCount() - getContentItemCount()); |
||||||
|
} |
||||||
|
return mAdapter.getItemViewType(position - getHeaderCount()); |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |
||||||
|
View contentView = mHeaderViews.get(viewType); |
||||||
|
if (contentView != null) { |
||||||
|
return new ViewHolder(contentView); |
||||||
|
} |
||||||
|
|
||||||
|
contentView = mFootViews.get(viewType); |
||||||
|
if (contentView != null) { |
||||||
|
return new ViewHolder(contentView); |
||||||
|
} |
||||||
|
|
||||||
|
final RecyclerView.ViewHolder viewHolder = mAdapter.onCreateViewHolder(parent, viewType); |
||||||
|
if (mOnItemClickListener != null) { |
||||||
|
viewHolder.itemView.setOnClickListener(new View.OnClickListener() { |
||||||
|
@Override |
||||||
|
public void onClick(View v) { |
||||||
|
mOnItemClickListener.onItemClick(v, viewHolder.getAdapterPosition()); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
if (mOnItemLongClickListener != null) { |
||||||
|
viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() { |
||||||
|
@Override |
||||||
|
public boolean onLongClick(View v) { |
||||||
|
mOnItemLongClickListener.onItemLongClick(v, viewHolder.getAdapterPosition()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
if (mSwipeMenuCreator == null) return viewHolder; |
||||||
|
|
||||||
|
contentView = mInflater.inflate(R.layout.x_recycler_view_item, parent, false); |
||||||
|
ViewGroup viewGroup = contentView.findViewById(R.id.swipe_content); |
||||||
|
viewGroup.addView(viewHolder.itemView); |
||||||
|
|
||||||
|
try { |
||||||
|
Field itemView = getSupperClass(viewHolder.getClass()).getDeclaredField("itemView"); |
||||||
|
if (!itemView.isAccessible()) itemView.setAccessible(true); |
||||||
|
itemView.set(viewHolder, contentView); |
||||||
|
} catch (Exception ignored) { |
||||||
|
} |
||||||
|
return viewHolder; |
||||||
|
} |
||||||
|
|
||||||
|
private Class<?> getSupperClass(Class<?> aClass) { |
||||||
|
Class<?> supperClass = aClass.getSuperclass(); |
||||||
|
if (supperClass != null && !supperClass.equals(Object.class)) { |
||||||
|
return getSupperClass(supperClass); |
||||||
|
} |
||||||
|
return aClass; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public final void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public final void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, |
||||||
|
@NonNull List<Object> payloads) { |
||||||
|
if (isHeaderOrFooter(holder)) return; |
||||||
|
|
||||||
|
View itemView = holder.itemView; |
||||||
|
position -= getHeaderCount(); |
||||||
|
|
||||||
|
if (itemView instanceof SwipeMenuLayout && mSwipeMenuCreator != null) { |
||||||
|
SwipeMenuLayout menuLayout = (SwipeMenuLayout) itemView; |
||||||
|
SwipeMenu leftMenu = new SwipeMenu(menuLayout); |
||||||
|
SwipeMenu rightMenu = new SwipeMenu(menuLayout); |
||||||
|
mSwipeMenuCreator.onCreateMenu(leftMenu, rightMenu, position); |
||||||
|
|
||||||
|
SwipeMenuView leftMenuView = (SwipeMenuView) menuLayout.getChildAt(0); |
||||||
|
if (leftMenu.hasMenuItems()) { |
||||||
|
leftMenuView.setOrientation(leftMenu.getOrientation()); |
||||||
|
leftMenuView.createMenu(holder, leftMenu, menuLayout, LEFT_DIRECTION, mOnItemMenuClickListener); |
||||||
|
} else if (leftMenuView.getChildCount() > 0) { |
||||||
|
leftMenuView.removeAllViews(); |
||||||
|
} |
||||||
|
|
||||||
|
SwipeMenuView rightMenuView = (SwipeMenuView) menuLayout.getChildAt(2); |
||||||
|
if (rightMenu.hasMenuItems()) { |
||||||
|
rightMenuView.setOrientation(rightMenu.getOrientation()); |
||||||
|
rightMenuView.createMenu(holder, rightMenu, menuLayout, RIGHT_DIRECTION, mOnItemMenuClickListener); |
||||||
|
} else if (rightMenuView.getChildCount() > 0) { |
||||||
|
rightMenuView.removeAllViews(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
mAdapter.onBindViewHolder(holder, position, payloads); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { |
||||||
|
mAdapter.onAttachedToRecyclerView(recyclerView); |
||||||
|
|
||||||
|
RecyclerView.LayoutManager lm = recyclerView.getLayoutManager(); |
||||||
|
if (lm instanceof GridLayoutManager) { |
||||||
|
final GridLayoutManager glm = (GridLayoutManager) lm; |
||||||
|
final GridLayoutManager.SpanSizeLookup originLookup = glm.getSpanSizeLookup(); |
||||||
|
|
||||||
|
glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { |
||||||
|
@Override |
||||||
|
public int getSpanSize(int position) { |
||||||
|
if (isHeaderOrFooter(position)) return glm.getSpanCount(); |
||||||
|
if (originLookup != null) return originLookup.getSpanSize(position); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onViewAttachedToWindow(@NonNull RecyclerView.ViewHolder holder) { |
||||||
|
if (isHeaderOrFooter(holder)) { |
||||||
|
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); |
||||||
|
if (lp instanceof StaggeredGridLayoutManager.LayoutParams) { |
||||||
|
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; |
||||||
|
p.setFullSpan(true); |
||||||
|
} |
||||||
|
} else { |
||||||
|
mAdapter.onViewAttachedToWindow(holder); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isHeaderOrFooter(RecyclerView.ViewHolder holder) { |
||||||
|
if (holder instanceof ViewHolder) return true; |
||||||
|
|
||||||
|
return isHeaderOrFooter(holder.getAdapterPosition()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isHeaderOrFooter(int position) { |
||||||
|
return isHeader(position) || isFooter(position); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isHeader(int position) { |
||||||
|
return position >= 0 && position < getHeaderCount(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isFooter(int position) { |
||||||
|
return position >= getHeaderCount() + getContentItemCount(); |
||||||
|
} |
||||||
|
|
||||||
|
public void addHeaderView(View view) { |
||||||
|
mHeaderViews.put(getHeaderCount() + BASE_ITEM_TYPE_HEADER, view); |
||||||
|
} |
||||||
|
|
||||||
|
public void addHeaderViewAndNotify(View view) { |
||||||
|
addHeaderView(view); |
||||||
|
notifyItemInserted(getHeaderCount() - 1); |
||||||
|
} |
||||||
|
|
||||||
|
public void removeHeaderViewAndNotify(View view) { |
||||||
|
int headerIndex = mHeaderViews.indexOfValue(view); |
||||||
|
if (headerIndex == -1) return; |
||||||
|
|
||||||
|
mHeaderViews.removeAt(headerIndex); |
||||||
|
notifyItemRemoved(headerIndex); |
||||||
|
} |
||||||
|
|
||||||
|
public void addFooterView(View view) { |
||||||
|
mFootViews.put(getFooterCount() + BASE_ITEM_TYPE_FOOTER, view); |
||||||
|
} |
||||||
|
|
||||||
|
public void addFooterViewAndNotify(View view) { |
||||||
|
addFooterView(view); |
||||||
|
notifyItemInserted(getHeaderCount() + getContentItemCount() + getFooterCount() - 1); |
||||||
|
} |
||||||
|
|
||||||
|
public void removeFooterViewAndNotify(View view) { |
||||||
|
int footerIndex = mFootViews.indexOfValue(view); |
||||||
|
if (footerIndex == -1) return; |
||||||
|
|
||||||
|
mFootViews.removeAt(footerIndex); |
||||||
|
notifyItemRemoved(getHeaderCount() + getContentItemCount() + footerIndex); |
||||||
|
} |
||||||
|
|
||||||
|
public int getHeaderCount() { |
||||||
|
return mHeaderViews.size(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getFooterCount() { |
||||||
|
return mFootViews.size(); |
||||||
|
} |
||||||
|
|
||||||
|
static class ViewHolder extends RecyclerView.ViewHolder { |
||||||
|
|
||||||
|
public ViewHolder(View itemView) { |
||||||
|
super(itemView); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public final void setHasStableIds(boolean hasStableIds) { |
||||||
|
super.setHasStableIds(hasStableIds); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getItemId(int position) { |
||||||
|
if (isHeaderOrFooter(position)) { |
||||||
|
return -position - 1; |
||||||
|
} |
||||||
|
|
||||||
|
position -= getHeaderCount(); |
||||||
|
return mAdapter.getItemId(position); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { |
||||||
|
if (!isHeaderOrFooter(holder)) mAdapter.onViewRecycled(holder); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onFailedToRecycleView(@NonNull RecyclerView.ViewHolder holder) { |
||||||
|
if (!isHeaderOrFooter(holder)) return mAdapter.onFailedToRecycleView(holder); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onViewDetachedFromWindow(@NonNull RecyclerView.ViewHolder holder) { |
||||||
|
if (!isHeaderOrFooter(holder)) mAdapter.onViewDetachedFromWindow(holder); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void registerAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) { |
||||||
|
super.registerAdapterDataObserver(observer); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void unregisterAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) { |
||||||
|
super.unregisterAdapterDataObserver(observer); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) { |
||||||
|
mAdapter.onDetachedFromRecyclerView(recyclerView); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/27. |
||||||
|
*/ |
||||||
|
interface Controller { |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is open? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isMenuOpen(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is open on the left? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isLeftMenuOpen(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is open on the right? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isRightMenuOpen(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is completely open? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isCompleteOpen(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is completely open on the left? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isLeftCompleteOpen(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is completely open on the right? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isRightCompleteOpen(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is open? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isMenuOpenNotEqual(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is open on the left? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isLeftMenuOpenNotEqual(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The menu is open on the right? |
||||||
|
* |
||||||
|
* @return true, otherwise false. |
||||||
|
*/ |
||||||
|
boolean isRightMenuOpenNotEqual(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Open the current menu. |
||||||
|
*/ |
||||||
|
void smoothOpenMenu(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Open the menu on left. |
||||||
|
*/ |
||||||
|
void smoothOpenLeftMenu(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Open the menu on right. |
||||||
|
*/ |
||||||
|
void smoothOpenRightMenu(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Open the menu on left for the duration. |
||||||
|
* |
||||||
|
* @param duration duration time. |
||||||
|
*/ |
||||||
|
void smoothOpenLeftMenu(int duration); |
||||||
|
|
||||||
|
/** |
||||||
|
* Open the menu on right for the duration. |
||||||
|
* |
||||||
|
* @param duration duration time. |
||||||
|
*/ |
||||||
|
void smoothOpenRightMenu(int duration); |
||||||
|
|
||||||
|
// ---------- closeMenu. ---------- //
|
||||||
|
|
||||||
|
/** |
||||||
|
* Smooth closed the menu. |
||||||
|
*/ |
||||||
|
void smoothCloseMenu(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Smooth closed the menu on the left. |
||||||
|
*/ |
||||||
|
void smoothCloseLeftMenu(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Smooth closed the menu on the right. |
||||||
|
*/ |
||||||
|
void smoothCloseRightMenu(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Smooth closed the menu for the duration. |
||||||
|
* |
||||||
|
* @param duration duration time. |
||||||
|
*/ |
||||||
|
void smoothCloseMenu(int duration); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,472 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2019 Zhenjie Yan |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.util.SparseBooleanArray; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.recyclerview.widget.GridLayoutManager; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Zhenjie Yan on 1/28/19. |
||||||
|
*/ |
||||||
|
public abstract class ExpandableAdapter<VH extends ExpandableAdapter.ViewHolder> extends RecyclerView.Adapter<VH> { |
||||||
|
|
||||||
|
private static final int TYPE_PARENT = 10000000; |
||||||
|
private static final int TYPE_CHILD = 20000000; |
||||||
|
|
||||||
|
private final SparseBooleanArray mExpandItemArray = new SparseBooleanArray(); |
||||||
|
private final List<Integer> mParentViewType = new ArrayList<>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Parent item is expanded. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
* |
||||||
|
* @return true, otherwise is false. |
||||||
|
*/ |
||||||
|
public final boolean isExpanded(int parentPosition) { |
||||||
|
return mExpandItemArray.get(parentPosition, false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Expand parent. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
*/ |
||||||
|
public final void expandParent(int parentPosition) { |
||||||
|
if (!isExpanded(parentPosition)) { |
||||||
|
mExpandItemArray.append(parentPosition, true); |
||||||
|
|
||||||
|
int position = positionFromParentPosition(parentPosition); |
||||||
|
int childCount = childItemCount(parentPosition); |
||||||
|
notifyItemRangeInserted(position + 1, childCount); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Collapse parent. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
*/ |
||||||
|
public final void collapseParent(int parentPosition) { |
||||||
|
if (isExpanded(parentPosition)) { |
||||||
|
mExpandItemArray.append(parentPosition, false); |
||||||
|
|
||||||
|
int position = positionFromParentPosition(parentPosition); |
||||||
|
int childCount = childItemCount(parentPosition); |
||||||
|
notifyItemRangeRemoved(position + 1, childCount); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notify any registered observers that the item at <code>parentPosition</code> has changed. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
*/ |
||||||
|
public final void notifyParentChanged(int parentPosition) { |
||||||
|
int position = positionFromParentPosition(parentPosition); |
||||||
|
notifyItemChanged(position); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notify any registered observers that the item reflected at <code>parentPosition</code> has been newly inserted. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
*/ |
||||||
|
public final void notifyParentInserted(int parentPosition) { |
||||||
|
int position = positionFromParentPosition(parentPosition); |
||||||
|
notifyItemInserted(position); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notify any registered observers that the item previously located at <code>parentPosition</code> has been removed |
||||||
|
* from the data set. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
*/ |
||||||
|
public final void notifyParentRemoved(int parentPosition) { |
||||||
|
int position = positionFromParentPosition(parentPosition); |
||||||
|
notifyItemRemoved(position); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notify any registered observers that the item at <code>parentPosition, childPosition</code> has changed. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
* @param childPosition positoin of child item. |
||||||
|
*/ |
||||||
|
public final void notifyChildChanged(int parentPosition, int childPosition) { |
||||||
|
int position = positionFromChildPosition(parentPosition, childPosition); |
||||||
|
notifyItemChanged(position); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notify any registered observers that the item reflected at <code>parentPosition, childPosition</code> has been |
||||||
|
* newly inserted. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
* @param childPosition positoin of child item. |
||||||
|
*/ |
||||||
|
public final void notifyChildInserted(int parentPosition, int childPosition) { |
||||||
|
int position = positionFromChildPosition(parentPosition, childPosition); |
||||||
|
notifyItemInserted(position); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notify any registered observers that the item previously located at <code>parentPosition, childPosition</code> |
||||||
|
* has been removed from the data set. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
* @param childPosition positoin of child item. |
||||||
|
*/ |
||||||
|
public final void notifyChildRemoved(int parentPosition, int childPosition) { |
||||||
|
int position = positionFromChildPosition(parentPosition, childPosition); |
||||||
|
notifyItemRemoved(position); |
||||||
|
} |
||||||
|
|
||||||
|
private int positionFromParentPosition(int parentPosition) { |
||||||
|
int itemCount = 0; |
||||||
|
|
||||||
|
int parentCount = parentItemCount(); |
||||||
|
for (int i = 0; i < parentCount; i++) { |
||||||
|
itemCount += 1; |
||||||
|
|
||||||
|
if (parentPosition == i) { |
||||||
|
return itemCount - 1; |
||||||
|
} else { |
||||||
|
if (isExpanded(i)) { |
||||||
|
itemCount += childItemCount(i); |
||||||
|
} else { |
||||||
|
// itemCount += 1;
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
throw new IllegalStateException("The parent position is invalid: " + parentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
private int positionFromChildPosition(int parentPosition, int childPosition) { |
||||||
|
int itemCount = 0; |
||||||
|
|
||||||
|
int parentCount = parentItemCount(); |
||||||
|
for (int i = 0; i < parentCount; i++) { |
||||||
|
itemCount += 1; |
||||||
|
|
||||||
|
if (parentPosition == i) { |
||||||
|
int childCount = childItemCount(parentPosition); |
||||||
|
if (childPosition < childCount) { |
||||||
|
itemCount += (childPosition + 1); |
||||||
|
return itemCount - 1; |
||||||
|
} |
||||||
|
|
||||||
|
throw new IllegalStateException("The child position is invalid: " + childPosition); |
||||||
|
} else { |
||||||
|
if (isExpanded(i)) { |
||||||
|
itemCount += childItemCount(i); |
||||||
|
} else { |
||||||
|
// itemCount += 1;
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
throw new IllegalStateException("The parent position is invalid: " + parentPosition); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public final int getItemCount() { |
||||||
|
int parentCount = parentItemCount(); |
||||||
|
for (int i = 0; i < parentCount; i++) { |
||||||
|
if (isExpanded(i)) { |
||||||
|
int childCount = childItemCount(i); |
||||||
|
parentCount += childCount; |
||||||
|
} else { |
||||||
|
// parentCount += 0;
|
||||||
|
} |
||||||
|
} |
||||||
|
return parentCount; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the total number of items in the parent. |
||||||
|
*/ |
||||||
|
public abstract int parentItemCount(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the total number of child items under parent. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
*/ |
||||||
|
public abstract int childItemCount(int parentPosition); |
||||||
|
|
||||||
|
@Override |
||||||
|
public final int getItemViewType(int position) { |
||||||
|
int parentPosition = parentItemPosition(position); |
||||||
|
if (isParentItem(position)) { |
||||||
|
int viewType = parentItemViewType(parentPosition); |
||||||
|
if (!mParentViewType.contains(viewType)) mParentViewType.add(viewType); |
||||||
|
return viewType; |
||||||
|
} else { |
||||||
|
int childPosition = childItemPosition(position); |
||||||
|
return childItemViewType(parentPosition, childPosition); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the view type of the parent item. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
*/ |
||||||
|
public int parentItemViewType(int parentPosition) { |
||||||
|
return TYPE_PARENT; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the view type of the child item. |
||||||
|
* |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
* @param childPosition position of child item. |
||||||
|
*/ |
||||||
|
public int childItemViewType(int parentPosition, int childPosition) { |
||||||
|
return TYPE_CHILD; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Item is a parent item. |
||||||
|
* |
||||||
|
* @param adapterPosition adapter position. |
||||||
|
* |
||||||
|
* @return true, otherwise is false. |
||||||
|
*/ |
||||||
|
public final boolean isParentItem(int adapterPosition) { |
||||||
|
int itemCount = 0; |
||||||
|
|
||||||
|
int parentCount = parentItemCount(); |
||||||
|
for (int i = 0; i < parentCount; i++) { |
||||||
|
if (itemCount == adapterPosition) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
itemCount += 1; |
||||||
|
|
||||||
|
if (isExpanded(i)) { |
||||||
|
itemCount += childItemCount(i); |
||||||
|
} else { |
||||||
|
// itemCount += 1;
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the position of the parent item from the adapter position. |
||||||
|
* |
||||||
|
* @param adapterPosition adapter position of item. |
||||||
|
*/ |
||||||
|
public final int parentItemPosition(int adapterPosition) { |
||||||
|
int itemCount = 0; |
||||||
|
for (int i = 0; i < parentItemCount(); i++) { |
||||||
|
itemCount += 1; |
||||||
|
|
||||||
|
if (isExpanded(i)) { |
||||||
|
int childCount = childItemCount(i); |
||||||
|
itemCount += childCount; |
||||||
|
} |
||||||
|
if (adapterPosition < itemCount) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
throw new IllegalStateException("The adapter position is not a parent type: " + adapterPosition); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the position of the child item from the adapter position. |
||||||
|
* |
||||||
|
* @param childAdapterPosition adapter position of child item. |
||||||
|
*/ |
||||||
|
public final int childItemPosition(int childAdapterPosition) { |
||||||
|
int itemCount = 0; |
||||||
|
|
||||||
|
int parentCount = parentItemCount(); |
||||||
|
for (int i = 0; i < parentCount; i++) { |
||||||
|
itemCount += 1; |
||||||
|
|
||||||
|
if (isExpanded(i)) { |
||||||
|
int childCount = childItemCount(i); |
||||||
|
itemCount += childCount; |
||||||
|
|
||||||
|
if (childAdapterPosition < itemCount) { |
||||||
|
return childCount - (itemCount - childAdapterPosition); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// itemCount += 1;
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
throw new IllegalStateException("The adapter position is invalid: " + childAdapterPosition); |
||||||
|
} |
||||||
|
|
||||||
|
@NonNull |
||||||
|
@Override |
||||||
|
public final VH onCreateViewHolder(@NonNull ViewGroup root, int viewType) { |
||||||
|
if (mParentViewType.contains(viewType)) return createParentHolder(root, viewType); |
||||||
|
return createChildHolder(root, viewType); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent an parent item. |
||||||
|
* |
||||||
|
* @param root the ViewGroup into which the new View will be added after it is bound to an adapter position. |
||||||
|
* @param viewType The view type of the new View. |
||||||
|
* |
||||||
|
* @return a new {@link ViewHolder} that holds a View of the given view type. |
||||||
|
*/ |
||||||
|
public abstract VH createParentHolder(@NonNull ViewGroup root, int viewType); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent an child item. |
||||||
|
* |
||||||
|
* @param root the ViewGroup into which the new View will be added after it is bound to an adapter position. |
||||||
|
* @param viewType The view type of the new View. |
||||||
|
* |
||||||
|
* @return a new {@link ViewHolder} that holds a View of the given view type. |
||||||
|
*/ |
||||||
|
public abstract VH createChildHolder(@NonNull ViewGroup root, int viewType); |
||||||
|
|
||||||
|
@Override |
||||||
|
public final void onBindViewHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) { |
||||||
|
int parentPosition = parentItemPosition(position); |
||||||
|
if (isParentItem(position)) { |
||||||
|
bindParentHolder(holder, parentPosition, payloads); |
||||||
|
} else { |
||||||
|
int childPosition = childItemPosition(position); |
||||||
|
bindChildHolder(holder, parentPosition, childPosition, payloads); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void bindParentHolder(@NonNull VH holder, int position, @NonNull List<Object> payloads) { |
||||||
|
bindParentHolder(holder, position); |
||||||
|
} |
||||||
|
|
||||||
|
public void bindChildHolder(@NonNull VH holder, int parentPosition, int position, @NonNull List<Object> payloads) { |
||||||
|
bindChildHolder(holder, parentPosition, position); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called by {@link RecyclerView} to display the data at the specified position. This method should update the |
||||||
|
* contents of the {@link ViewHolder#itemView} to reflect the item at the given position. |
||||||
|
* |
||||||
|
* @param holder parent holder. |
||||||
|
* @param position position of parent item. |
||||||
|
*/ |
||||||
|
public abstract void bindParentHolder(@NonNull VH holder, int position); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called by {@link RecyclerView} to display the data at the specified position. This method should update the * |
||||||
|
* contents of the {@link ViewHolder#itemView} to reflect the item at the given position. |
||||||
|
* |
||||||
|
* @param holder child holder. |
||||||
|
* @param parentPosition position of parent item. |
||||||
|
* @param position position of child position. |
||||||
|
*/ |
||||||
|
public abstract void bindChildHolder(@NonNull VH holder, int parentPosition, int position); |
||||||
|
|
||||||
|
@Deprecated |
||||||
|
@Override |
||||||
|
public final void onBindViewHolder(@NonNull VH holder, int position) { |
||||||
|
} |
||||||
|
|
||||||
|
public static abstract class ViewHolder extends RecyclerView.ViewHolder { |
||||||
|
|
||||||
|
private ExpandableAdapter mAdapter; |
||||||
|
|
||||||
|
public ViewHolder(@NonNull View itemView, ExpandableAdapter adapter) { |
||||||
|
super(itemView); |
||||||
|
this.mAdapter = adapter; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Determine if the current viewholder is a parent item. |
||||||
|
* |
||||||
|
* @return true, otherwise is false. |
||||||
|
*/ |
||||||
|
public final boolean isParentItem() { |
||||||
|
return mAdapter.isParentItem(getAdapterPosition()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the position of parent item. |
||||||
|
*/ |
||||||
|
public final int parentItemPosition() { |
||||||
|
return mAdapter.parentItemPosition(getAdapterPosition()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the position of child item. |
||||||
|
*/ |
||||||
|
public final int childItemPosition() { |
||||||
|
if (isParentItem()) throw new IllegalStateException("This item is not a child item."); |
||||||
|
return mAdapter.childItemPosition(getAdapterPosition()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Parent item is expanded. |
||||||
|
* |
||||||
|
* @return true, otherwise is false. |
||||||
|
*/ |
||||||
|
public final boolean isParentExpanded() { |
||||||
|
return mAdapter.isExpanded(parentItemPosition()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { |
||||||
|
RecyclerView.LayoutManager lm = recyclerView.getLayoutManager(); |
||||||
|
if (lm instanceof GridLayoutManager) { |
||||||
|
final GridLayoutManager glm = (GridLayoutManager)lm; |
||||||
|
final GridLayoutManager.SpanSizeLookup originLookup = glm.getSpanSizeLookup(); |
||||||
|
|
||||||
|
glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { |
||||||
|
@Override |
||||||
|
public int getSpanSize(int position) { |
||||||
|
if (isParentItem(position)) return glm.getSpanCount(); |
||||||
|
if (originLookup != null) return originLookup.getSpanSize(position); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onViewAttachedToWindow(@NonNull VH holder) { |
||||||
|
if (isParentItem(holder.getAdapterPosition())) { |
||||||
|
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); |
||||||
|
if (lp instanceof StaggeredGridLayoutManager.LayoutParams) { |
||||||
|
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams)lp; |
||||||
|
p.setFullSpan(true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,80 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
import android.widget.OverScroller; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/22. |
||||||
|
*/ |
||||||
|
abstract class Horizontal { |
||||||
|
|
||||||
|
private int direction; |
||||||
|
private View menuView; |
||||||
|
protected Checker mChecker; |
||||||
|
|
||||||
|
public Horizontal(int direction, View menuView) { |
||||||
|
this.direction = direction; |
||||||
|
this.menuView = menuView; |
||||||
|
mChecker = new Checker(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean canSwipe() { |
||||||
|
if (menuView instanceof ViewGroup) { |
||||||
|
return ((ViewGroup)menuView).getChildCount() > 0; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isCompleteClose(int scrollX) { |
||||||
|
int i = -getMenuView().getWidth() * getDirection(); |
||||||
|
return scrollX == 0 && i != 0; |
||||||
|
} |
||||||
|
|
||||||
|
public abstract boolean isMenuOpen(int scrollX); |
||||||
|
|
||||||
|
public abstract boolean isMenuOpenNotEqual(int scrollX); |
||||||
|
|
||||||
|
public abstract void autoOpenMenu(OverScroller scroller, int scrollX, int duration); |
||||||
|
|
||||||
|
public abstract void autoCloseMenu(OverScroller scroller, int scrollX, int duration); |
||||||
|
|
||||||
|
public abstract Checker checkXY(int x, int y); |
||||||
|
|
||||||
|
public abstract boolean isClickOnContentView(int contentViewWidth, float x); |
||||||
|
|
||||||
|
public int getDirection() { |
||||||
|
return direction; |
||||||
|
} |
||||||
|
|
||||||
|
public View getMenuView() { |
||||||
|
return menuView; |
||||||
|
} |
||||||
|
|
||||||
|
public int getMenuWidth() { |
||||||
|
return menuView.getWidth(); |
||||||
|
} |
||||||
|
|
||||||
|
public static final class Checker { |
||||||
|
|
||||||
|
public int x; |
||||||
|
public int y; |
||||||
|
public boolean shouldResetSwipe; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.view.View; |
||||||
|
import android.widget.OverScroller; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/22. |
||||||
|
*/ |
||||||
|
class LeftHorizontal extends Horizontal { |
||||||
|
|
||||||
|
public LeftHorizontal(View menuView) { |
||||||
|
super(SwipeRecyclerView.LEFT_DIRECTION, menuView); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isMenuOpen(int scrollX) { |
||||||
|
int i = -getMenuView().getWidth() * getDirection(); |
||||||
|
return scrollX <= i && i != 0; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isMenuOpenNotEqual(int scrollX) { |
||||||
|
return scrollX < -getMenuView().getWidth() * getDirection(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void autoOpenMenu(OverScroller scroller, int scrollX, int duration) { |
||||||
|
scroller.startScroll(Math.abs(scrollX), 0, getMenuView().getWidth() - Math.abs(scrollX), 0, duration); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void autoCloseMenu(OverScroller scroller, int scrollX, int duration) { |
||||||
|
scroller.startScroll(-Math.abs(scrollX), 0, Math.abs(scrollX), 0, duration); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Checker checkXY(int x, int y) { |
||||||
|
mChecker.x = x; |
||||||
|
mChecker.y = y; |
||||||
|
mChecker.shouldResetSwipe = false; |
||||||
|
if (mChecker.x == 0) { |
||||||
|
mChecker.shouldResetSwipe = true; |
||||||
|
} |
||||||
|
if (mChecker.x >= 0) { |
||||||
|
mChecker.x = 0; |
||||||
|
} |
||||||
|
if (mChecker.x <= -getMenuView().getWidth()) { |
||||||
|
mChecker.x = -getMenuView().getWidth(); |
||||||
|
} |
||||||
|
return mChecker; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isClickOnContentView(int contentViewWidth, float x) { |
||||||
|
return x > getMenuView().getWidth(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/7/21. |
||||||
|
*/ |
||||||
|
public interface OnItemClickListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* @param view target view. |
||||||
|
* @param adapterPosition position of item. |
||||||
|
*/ |
||||||
|
void onItemClick(View view, int adapterPosition); |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/7/21. |
||||||
|
*/ |
||||||
|
public interface OnItemLongClickListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* @param view target view. |
||||||
|
* @param adapterPosition position of item. |
||||||
|
*/ |
||||||
|
void onItemLongClick(View view, int adapterPosition); |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/26. |
||||||
|
*/ |
||||||
|
public interface OnItemMenuClickListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* @param menuBridge menu bridge. |
||||||
|
* @param adapterPosition position of item. |
||||||
|
*/ |
||||||
|
void onItemClick(SwipeMenuBridge menuBridge, int adapterPosition); |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.view.View; |
||||||
|
import android.widget.OverScroller; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/22. |
||||||
|
*/ |
||||||
|
class RightHorizontal extends Horizontal { |
||||||
|
|
||||||
|
public RightHorizontal(View menuView) { |
||||||
|
super(SwipeRecyclerView.RIGHT_DIRECTION, menuView); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isMenuOpen(int scrollX) { |
||||||
|
int i = -getMenuView().getWidth() * getDirection(); |
||||||
|
return scrollX >= i && i != 0; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isMenuOpenNotEqual(int scrollX) { |
||||||
|
return scrollX > -getMenuView().getWidth() * getDirection(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void autoOpenMenu(OverScroller scroller, int scrollX, int duration) { |
||||||
|
scroller.startScroll(Math.abs(scrollX), 0, getMenuView().getWidth() - Math.abs(scrollX), 0, duration); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void autoCloseMenu(OverScroller scroller, int scrollX, int duration) { |
||||||
|
scroller.startScroll(-Math.abs(scrollX), 0, Math.abs(scrollX), 0, duration); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Checker checkXY(int x, int y) { |
||||||
|
mChecker.x = x; |
||||||
|
mChecker.y = y; |
||||||
|
mChecker.shouldResetSwipe = false; |
||||||
|
if (mChecker.x == 0) { |
||||||
|
mChecker.shouldResetSwipe = true; |
||||||
|
} |
||||||
|
if (mChecker.x < 0) { |
||||||
|
mChecker.x = 0; |
||||||
|
} |
||||||
|
if (mChecker.x > getMenuView().getWidth()) { |
||||||
|
mChecker.x = getMenuView().getWidth(); |
||||||
|
} |
||||||
|
return mChecker; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isClickOnContentView(int contentViewWidth, float x) { |
||||||
|
return x < (contentViewWidth - getMenuView().getWidth()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.widget.LinearLayout; |
||||||
|
|
||||||
|
import androidx.annotation.FloatRange; |
||||||
|
import androidx.annotation.IntDef; |
||||||
|
import androidx.annotation.IntRange; |
||||||
|
|
||||||
|
import java.lang.annotation.Retention; |
||||||
|
import java.lang.annotation.RetentionPolicy; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/22. |
||||||
|
*/ |
||||||
|
public class SwipeMenu { |
||||||
|
|
||||||
|
@IntDef({HORIZONTAL, VERTICAL}) |
||||||
|
@Retention(RetentionPolicy.SOURCE) |
||||||
|
public @interface OrientationMode {} |
||||||
|
|
||||||
|
public static final int HORIZONTAL = LinearLayout.HORIZONTAL; |
||||||
|
public static final int VERTICAL = LinearLayout.VERTICAL; |
||||||
|
|
||||||
|
private SwipeMenuLayout mMenuLayout; |
||||||
|
private int mOrientation; |
||||||
|
private List<SwipeMenuItem> mSwipeMenuItems; |
||||||
|
|
||||||
|
public SwipeMenu(SwipeMenuLayout menuLayout) { |
||||||
|
this.mMenuLayout = menuLayout; |
||||||
|
this.mOrientation = SwipeMenu.HORIZONTAL; |
||||||
|
this.mSwipeMenuItems = new ArrayList<>(2); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set a percentage. |
||||||
|
* |
||||||
|
* @param openPercent such as 0.5F. |
||||||
|
*/ |
||||||
|
public void setOpenPercent(@FloatRange(from = 0.1, to = 1) float openPercent) { |
||||||
|
mMenuLayout.setOpenPercent(openPercent); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The duration of the set. |
||||||
|
* |
||||||
|
* @param scrollerDuration such 500. |
||||||
|
*/ |
||||||
|
public void setScrollerDuration(@IntRange(from = 1) int scrollerDuration) { |
||||||
|
mMenuLayout.setScrollerDuration(scrollerDuration); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the menu mOrientation. |
||||||
|
* |
||||||
|
* @param orientation use {@link SwipeMenu#HORIZONTAL} or {@link SwipeMenu#VERTICAL}. |
||||||
|
* |
||||||
|
* @see SwipeMenu#HORIZONTAL |
||||||
|
* @see SwipeMenu#VERTICAL |
||||||
|
*/ |
||||||
|
public void setOrientation(@OrientationMode int orientation) { |
||||||
|
this.mOrientation = orientation; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the menu mOrientation. |
||||||
|
* |
||||||
|
* @return {@link SwipeMenu#HORIZONTAL} or {@link SwipeMenu#VERTICAL}. |
||||||
|
*/ |
||||||
|
@OrientationMode |
||||||
|
public int getOrientation() { |
||||||
|
return mOrientation; |
||||||
|
} |
||||||
|
|
||||||
|
public void addMenuItem(SwipeMenuItem item) { |
||||||
|
mSwipeMenuItems.add(item); |
||||||
|
} |
||||||
|
|
||||||
|
public void removeMenuItem(SwipeMenuItem item) { |
||||||
|
mSwipeMenuItems.remove(item); |
||||||
|
} |
||||||
|
|
||||||
|
public List<SwipeMenuItem> getMenuItems() { |
||||||
|
return mSwipeMenuItems; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean hasMenuItems() { |
||||||
|
return !mSwipeMenuItems.isEmpty(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/7/20. |
||||||
|
*/ |
||||||
|
public class SwipeMenuBridge { |
||||||
|
|
||||||
|
private final Controller mController; |
||||||
|
private final int mDirection; |
||||||
|
private final int mPosition; |
||||||
|
|
||||||
|
public SwipeMenuBridge(Controller controller, int direction, int position) { |
||||||
|
this.mController = controller; |
||||||
|
this.mDirection = direction; |
||||||
|
this.mPosition = position; |
||||||
|
} |
||||||
|
|
||||||
|
@SwipeRecyclerView.DirectionMode |
||||||
|
public int getDirection() { |
||||||
|
return mDirection; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the position of button in the menu. |
||||||
|
*/ |
||||||
|
public int getPosition() { |
||||||
|
return mPosition; |
||||||
|
} |
||||||
|
|
||||||
|
public void closeMenu() { |
||||||
|
mController.smoothCloseMenu(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/26. |
||||||
|
*/ |
||||||
|
public interface SwipeMenuCreator { |
||||||
|
|
||||||
|
/** |
||||||
|
* Create menu for recyclerVie item. |
||||||
|
* |
||||||
|
* @param leftMenu the menu on the left. |
||||||
|
* @param rightMenu the menu on the right. |
||||||
|
* @param position the position of item. |
||||||
|
*/ |
||||||
|
void onCreateMenu(SwipeMenu leftMenu, SwipeMenu rightMenu, int position); |
||||||
|
} |
@ -0,0 +1,166 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.res.ColorStateList; |
||||||
|
import android.graphics.Typeface; |
||||||
|
import android.graphics.drawable.ColorDrawable; |
||||||
|
import android.graphics.drawable.Drawable; |
||||||
|
|
||||||
|
import androidx.annotation.ColorInt; |
||||||
|
import androidx.annotation.ColorRes; |
||||||
|
import androidx.annotation.DrawableRes; |
||||||
|
import androidx.annotation.StringRes; |
||||||
|
import androidx.annotation.StyleRes; |
||||||
|
import androidx.core.content.ContextCompat; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/26. |
||||||
|
*/ |
||||||
|
public class SwipeMenuItem { |
||||||
|
|
||||||
|
private Context mContext; |
||||||
|
private Drawable background; |
||||||
|
private Drawable icon; |
||||||
|
private String title; |
||||||
|
private ColorStateList titleColor; |
||||||
|
private int titleSize; |
||||||
|
private Typeface textTypeface; |
||||||
|
private int textAppearance; |
||||||
|
private int width = -2; |
||||||
|
private int height = -2; |
||||||
|
private int weight = 0; |
||||||
|
|
||||||
|
public SwipeMenuItem(Context context) { |
||||||
|
mContext = context; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setBackground(@DrawableRes int resId) { |
||||||
|
return setBackground(ContextCompat.getDrawable(mContext, resId)); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setBackground(Drawable background) { |
||||||
|
this.background = background; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setBackgroundColorResource(@ColorRes int color) { |
||||||
|
return setBackgroundColor(ContextCompat.getColor(mContext, color)); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setBackgroundColor(@ColorInt int color) { |
||||||
|
this.background = new ColorDrawable(color); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Drawable getBackground() { |
||||||
|
return background; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setImage(@DrawableRes int resId) { |
||||||
|
return setImage(ContextCompat.getDrawable(mContext, resId)); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setImage(Drawable icon) { |
||||||
|
this.icon = icon; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Drawable getImage() { |
||||||
|
return icon; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setText(@StringRes int resId) { |
||||||
|
return setText(mContext.getString(resId)); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setText(String title) { |
||||||
|
this.title = title; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public String getText() { |
||||||
|
return title; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setTextColorResource(@ColorRes int titleColor) { |
||||||
|
return setTextColor(ContextCompat.getColor(mContext, titleColor)); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setTextColor(@ColorInt int titleColor) { |
||||||
|
this.titleColor = ColorStateList.valueOf(titleColor); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public ColorStateList getTitleColor() { |
||||||
|
return titleColor; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setTextSize(int titleSize) { |
||||||
|
this.titleSize = titleSize; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public int getTextSize() { |
||||||
|
return titleSize; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setTextAppearance(@StyleRes int textAppearance) { |
||||||
|
this.textAppearance = textAppearance; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public int getTextAppearance() { |
||||||
|
return textAppearance; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setTextTypeface(Typeface textTypeface) { |
||||||
|
this.textTypeface = textTypeface; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Typeface getTextTypeface() { |
||||||
|
return textTypeface; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setWidth(int width) { |
||||||
|
this.width = width; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public int getWidth() { |
||||||
|
return width; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setHeight(int height) { |
||||||
|
this.height = height; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public int getHeight() { |
||||||
|
return height; |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuItem setWeight(int weight) { |
||||||
|
this.weight = weight; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public int getWeight() { |
||||||
|
return weight; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,531 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.res.TypedArray; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.Gravity; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.VelocityTracker; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewConfiguration; |
||||||
|
import android.widget.FrameLayout; |
||||||
|
import android.widget.OverScroller; |
||||||
|
import android.widget.TextView; |
||||||
|
|
||||||
|
import androidx.core.view.ViewCompat; |
||||||
|
|
||||||
|
import com.project.survey.R; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/27. |
||||||
|
*/ |
||||||
|
public class SwipeMenuLayout extends FrameLayout implements Controller { |
||||||
|
|
||||||
|
public static final int DEFAULT_SCROLLER_DURATION = 200; |
||||||
|
|
||||||
|
private int mLeftViewId = 0; |
||||||
|
private int mContentViewId = 0; |
||||||
|
private int mRightViewId = 0; |
||||||
|
|
||||||
|
private float mOpenPercent = 0.5f; |
||||||
|
private int mScrollerDuration = DEFAULT_SCROLLER_DURATION; |
||||||
|
|
||||||
|
private int mScaledTouchSlop; |
||||||
|
private int mLastX; |
||||||
|
private int mLastY; |
||||||
|
private int mDownX; |
||||||
|
private int mDownY; |
||||||
|
private View mContentView; |
||||||
|
private LeftHorizontal mSwipeLeftHorizontal; |
||||||
|
private RightHorizontal mSwipeRightHorizontal; |
||||||
|
private Horizontal mSwipeCurrentHorizontal; |
||||||
|
private boolean shouldResetSwipe; |
||||||
|
private boolean mDragging; |
||||||
|
private boolean swipeEnable = true; |
||||||
|
private OverScroller mScroller; |
||||||
|
private VelocityTracker mVelocityTracker; |
||||||
|
private int mScaledMinimumFlingVelocity; |
||||||
|
private int mScaledMaximumFlingVelocity; |
||||||
|
|
||||||
|
|
||||||
|
public SwipeMenuLayout(Context context) { |
||||||
|
this(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuLayout(Context context, AttributeSet attrs) { |
||||||
|
this(context, attrs, 0); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuLayout(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
setClickable(true); |
||||||
|
|
||||||
|
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SwipeMenuLayout); |
||||||
|
mLeftViewId = typedArray.getResourceId(R.styleable.SwipeMenuLayout_leftViewId, mLeftViewId); |
||||||
|
mContentViewId = typedArray.getResourceId(R.styleable.SwipeMenuLayout_contentViewId, mContentViewId); |
||||||
|
mRightViewId = typedArray.getResourceId(R.styleable.SwipeMenuLayout_rightViewId, mRightViewId); |
||||||
|
typedArray.recycle(); |
||||||
|
|
||||||
|
ViewConfiguration configuration = ViewConfiguration.get(getContext()); |
||||||
|
mScaledTouchSlop = configuration.getScaledTouchSlop(); |
||||||
|
mScaledMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); |
||||||
|
mScaledMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity(); |
||||||
|
|
||||||
|
mScroller = new OverScroller(getContext()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onFinishInflate() { |
||||||
|
super.onFinishInflate(); |
||||||
|
if (mLeftViewId != 0 && mSwipeLeftHorizontal == null) { |
||||||
|
View view = findViewById(mLeftViewId); |
||||||
|
mSwipeLeftHorizontal = new LeftHorizontal(view); |
||||||
|
} |
||||||
|
if (mRightViewId != 0 && mSwipeRightHorizontal == null) { |
||||||
|
View view = findViewById(mRightViewId); |
||||||
|
mSwipeRightHorizontal = new RightHorizontal(view); |
||||||
|
} |
||||||
|
if (mContentViewId != 0 && mContentView == null) { |
||||||
|
mContentView = findViewById(mContentViewId); |
||||||
|
} else { |
||||||
|
TextView errorView = new TextView(getContext()); |
||||||
|
errorView.setClickable(true); |
||||||
|
errorView.setGravity(Gravity.CENTER); |
||||||
|
errorView.setTextSize(16); |
||||||
|
errorView.setText("You may not have set the ContentView."); |
||||||
|
mContentView = errorView; |
||||||
|
addView(mContentView); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set whether open swipe. Default is true. |
||||||
|
* |
||||||
|
* @param swipeEnable true open, otherwise false. |
||||||
|
*/ |
||||||
|
public void setSwipeEnable(boolean swipeEnable) { |
||||||
|
this.swipeEnable = swipeEnable; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Open the swipe function of the Item? |
||||||
|
* |
||||||
|
* @return open is true, otherwise is false. |
||||||
|
*/ |
||||||
|
public boolean isSwipeEnable() { |
||||||
|
return swipeEnable; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set open percentage. |
||||||
|
* |
||||||
|
* @param openPercent such as 0.5F. |
||||||
|
*/ |
||||||
|
public void setOpenPercent(float openPercent) { |
||||||
|
this.mOpenPercent = openPercent; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get open percentage. |
||||||
|
* |
||||||
|
* @return such as 0.5F. |
||||||
|
*/ |
||||||
|
public float getOpenPercent() { |
||||||
|
return mOpenPercent; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The duration of the set. |
||||||
|
* |
||||||
|
* @param scrollerDuration such as 500. |
||||||
|
*/ |
||||||
|
public void setScrollerDuration(int scrollerDuration) { |
||||||
|
this.mScrollerDuration = scrollerDuration; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) { |
||||||
|
boolean isIntercepted = super.onInterceptTouchEvent(ev); |
||||||
|
if (!isSwipeEnable()) { |
||||||
|
return isIntercepted; |
||||||
|
} |
||||||
|
|
||||||
|
int action = ev.getAction(); |
||||||
|
switch (action) { |
||||||
|
case MotionEvent.ACTION_DOWN: { |
||||||
|
mDownX = mLastX = (int) ev.getX(); |
||||||
|
mDownY = (int) ev.getY(); |
||||||
|
return false; |
||||||
|
} |
||||||
|
case MotionEvent.ACTION_MOVE: { |
||||||
|
int disX = (int) (ev.getX() - mDownX); |
||||||
|
int disY = (int) (ev.getY() - mDownY); |
||||||
|
return Math.abs(disX) > mScaledTouchSlop && Math.abs(disX) > Math.abs(disY); |
||||||
|
} |
||||||
|
case MotionEvent.ACTION_UP: { |
||||||
|
boolean isClick = mSwipeCurrentHorizontal != null && |
||||||
|
mSwipeCurrentHorizontal.isClickOnContentView(getWidth(), ev.getX()); |
||||||
|
if (isMenuOpen() && isClick) { |
||||||
|
smoothCloseMenu(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
case MotionEvent.ACTION_CANCEL: { |
||||||
|
if (!mScroller.isFinished()) mScroller.abortAnimation(); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
return isIntercepted; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onTouchEvent(MotionEvent ev) { |
||||||
|
if (!isSwipeEnable()) { |
||||||
|
return super.onTouchEvent(ev); |
||||||
|
} |
||||||
|
|
||||||
|
if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain(); |
||||||
|
mVelocityTracker.addMovement(ev); |
||||||
|
int dx; |
||||||
|
int dy; |
||||||
|
int action = ev.getAction(); |
||||||
|
switch (action) { |
||||||
|
case MotionEvent.ACTION_DOWN: { |
||||||
|
mLastX = (int) ev.getX(); |
||||||
|
mLastY = (int) ev.getY(); |
||||||
|
break; |
||||||
|
} |
||||||
|
case MotionEvent.ACTION_MOVE: { |
||||||
|
int disX = (int) (mLastX - ev.getX()); |
||||||
|
int disY = (int) (mLastY - ev.getY()); |
||||||
|
if (!mDragging && Math.abs(disX) > mScaledTouchSlop && Math.abs(disX) > Math.abs(disY)) { |
||||||
|
mDragging = true; |
||||||
|
} |
||||||
|
if (mDragging) { |
||||||
|
if (mSwipeCurrentHorizontal == null || shouldResetSwipe) { |
||||||
|
if (disX < 0) { |
||||||
|
if (mSwipeLeftHorizontal != null) { |
||||||
|
mSwipeCurrentHorizontal = mSwipeLeftHorizontal; |
||||||
|
} else { |
||||||
|
mSwipeCurrentHorizontal = mSwipeRightHorizontal; |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (mSwipeRightHorizontal != null) { |
||||||
|
mSwipeCurrentHorizontal = mSwipeRightHorizontal; |
||||||
|
} else { |
||||||
|
mSwipeCurrentHorizontal = mSwipeLeftHorizontal; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
scrollBy(disX, 0); |
||||||
|
mLastX = (int) ev.getX(); |
||||||
|
mLastY = (int) ev.getY(); |
||||||
|
shouldResetSwipe = false; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
case MotionEvent.ACTION_UP: { |
||||||
|
dx = (int) (mDownX - ev.getX()); |
||||||
|
dy = (int) (mDownY - ev.getY()); |
||||||
|
mDragging = false; |
||||||
|
mVelocityTracker.computeCurrentVelocity(1000, mScaledMaximumFlingVelocity); |
||||||
|
int velocityX = (int) mVelocityTracker.getXVelocity(); |
||||||
|
int velocity = Math.abs(velocityX); |
||||||
|
if (velocity > mScaledMinimumFlingVelocity) { |
||||||
|
if (mSwipeCurrentHorizontal != null) { |
||||||
|
int duration = getSwipeDuration(ev, velocity); |
||||||
|
if (mSwipeCurrentHorizontal instanceof RightHorizontal) { |
||||||
|
if (velocityX < 0) { |
||||||
|
smoothOpenMenu(duration); |
||||||
|
} else { |
||||||
|
smoothCloseMenu(duration); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (velocityX > 0) { |
||||||
|
smoothOpenMenu(duration); |
||||||
|
} else { |
||||||
|
smoothCloseMenu(duration); |
||||||
|
} |
||||||
|
} |
||||||
|
ViewCompat.postInvalidateOnAnimation(this); |
||||||
|
} |
||||||
|
} else { |
||||||
|
judgeOpenClose(dx, dy); |
||||||
|
} |
||||||
|
mVelocityTracker.clear(); |
||||||
|
mVelocityTracker.recycle(); |
||||||
|
mVelocityTracker = null; |
||||||
|
if (Math.abs(mDownX - ev.getX()) > mScaledTouchSlop || |
||||||
|
Math.abs(mDownY - ev.getY()) > mScaledTouchSlop || isLeftMenuOpen() || isRightMenuOpen()) { |
||||||
|
ev.setAction(MotionEvent.ACTION_CANCEL); |
||||||
|
super.onTouchEvent(ev); |
||||||
|
return true; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
case MotionEvent.ACTION_CANCEL: { |
||||||
|
mDragging = false; |
||||||
|
if (!mScroller.isFinished()) { |
||||||
|
mScroller.abortAnimation(); |
||||||
|
} else { |
||||||
|
dx = (int) (mDownX - ev.getX()); |
||||||
|
dy = (int) (mDownY - ev.getY()); |
||||||
|
judgeOpenClose(dx, dy); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return super.onTouchEvent(ev); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* compute finish duration. |
||||||
|
* |
||||||
|
* @param ev up event. |
||||||
|
* @param velocity velocity x. |
||||||
|
* @return finish duration. |
||||||
|
*/ |
||||||
|
private int getSwipeDuration(MotionEvent ev, int velocity) { |
||||||
|
int sx = getScrollX(); |
||||||
|
int dx = (int) (ev.getX() - sx); |
||||||
|
final int width = mSwipeCurrentHorizontal.getMenuWidth(); |
||||||
|
final int halfWidth = width / 2; |
||||||
|
final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width); |
||||||
|
final float distance = halfWidth + halfWidth * distanceInfluenceForSnapDuration(distanceRatio); |
||||||
|
int duration; |
||||||
|
if (velocity > 0) { |
||||||
|
duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); |
||||||
|
} else { |
||||||
|
final float pageDelta = (float) Math.abs(dx) / width; |
||||||
|
duration = (int) ((pageDelta + 1) * 100); |
||||||
|
} |
||||||
|
duration = Math.min(duration, mScrollerDuration); |
||||||
|
return duration; |
||||||
|
} |
||||||
|
|
||||||
|
float distanceInfluenceForSnapDuration(float f) { |
||||||
|
f -= 0.5f; // center the values about 0.
|
||||||
|
f *= 0.3f * Math.PI / 2.0f; |
||||||
|
return (float) Math.sin(f); |
||||||
|
} |
||||||
|
|
||||||
|
private void judgeOpenClose(int dx, int dy) { |
||||||
|
if (mSwipeCurrentHorizontal != null) { |
||||||
|
if (Math.abs(getScrollX()) >= |
||||||
|
(mSwipeCurrentHorizontal.getMenuView().getWidth() * mOpenPercent)) { // auto open
|
||||||
|
if (Math.abs(dx) > mScaledTouchSlop || Math.abs(dy) > mScaledTouchSlop) { // swipe up
|
||||||
|
if (isMenuOpenNotEqual()) { |
||||||
|
smoothCloseMenu(); |
||||||
|
} else { |
||||||
|
smoothOpenMenu(); |
||||||
|
} |
||||||
|
} else { // normal up
|
||||||
|
if (isMenuOpen()) { |
||||||
|
smoothCloseMenu(); |
||||||
|
} else { |
||||||
|
smoothOpenMenu(); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { // auto closeMenu
|
||||||
|
smoothCloseMenu(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void scrollTo(int x, int y) { |
||||||
|
if (mSwipeCurrentHorizontal == null) { |
||||||
|
super.scrollTo(x, y); |
||||||
|
} else { |
||||||
|
Horizontal.Checker checker = mSwipeCurrentHorizontal.checkXY(x, y); |
||||||
|
shouldResetSwipe = checker.shouldResetSwipe; |
||||||
|
if (checker.x != getScrollX()) { |
||||||
|
super.scrollTo(checker.x, checker.y); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void computeScroll() { |
||||||
|
if (mScroller.computeScrollOffset() && mSwipeCurrentHorizontal != null) { |
||||||
|
if (mSwipeCurrentHorizontal instanceof RightHorizontal) { |
||||||
|
scrollTo(Math.abs(mScroller.getCurrX()), 0); |
||||||
|
invalidate(); |
||||||
|
} else { |
||||||
|
scrollTo(-Math.abs(mScroller.getCurrX()), 0); |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean hasLeftMenu() { |
||||||
|
return mSwipeLeftHorizontal != null && mSwipeLeftHorizontal.canSwipe(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean hasRightMenu() { |
||||||
|
return mSwipeRightHorizontal != null && mSwipeRightHorizontal.canSwipe(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isMenuOpen() { |
||||||
|
return isLeftMenuOpen() || isRightMenuOpen(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isLeftMenuOpen() { |
||||||
|
return mSwipeLeftHorizontal != null && mSwipeLeftHorizontal.isMenuOpen(getScrollX()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isRightMenuOpen() { |
||||||
|
return mSwipeRightHorizontal != null && mSwipeRightHorizontal.isMenuOpen(getScrollX()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isCompleteOpen() { |
||||||
|
return isLeftCompleteOpen() || isRightMenuOpen(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isLeftCompleteOpen() { |
||||||
|
return mSwipeLeftHorizontal != null && !mSwipeLeftHorizontal.isCompleteClose(getScrollX()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isRightCompleteOpen() { |
||||||
|
return mSwipeRightHorizontal != null && !mSwipeRightHorizontal.isCompleteClose(getScrollX()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isMenuOpenNotEqual() { |
||||||
|
return isLeftMenuOpenNotEqual() || isRightMenuOpenNotEqual(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isLeftMenuOpenNotEqual() { |
||||||
|
return mSwipeLeftHorizontal != null && mSwipeLeftHorizontal.isMenuOpenNotEqual(getScrollX()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isRightMenuOpenNotEqual() { |
||||||
|
return mSwipeRightHorizontal != null && mSwipeRightHorizontal.isMenuOpenNotEqual(getScrollX()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothOpenMenu() { |
||||||
|
smoothOpenMenu(mScrollerDuration); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothOpenLeftMenu() { |
||||||
|
smoothOpenLeftMenu(mScrollerDuration); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothOpenRightMenu() { |
||||||
|
smoothOpenRightMenu(mScrollerDuration); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothOpenLeftMenu(int duration) { |
||||||
|
if (mSwipeLeftHorizontal != null) { |
||||||
|
mSwipeCurrentHorizontal = mSwipeLeftHorizontal; |
||||||
|
smoothOpenMenu(duration); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothOpenRightMenu(int duration) { |
||||||
|
if (mSwipeRightHorizontal != null) { |
||||||
|
mSwipeCurrentHorizontal = mSwipeRightHorizontal; |
||||||
|
smoothOpenMenu(duration); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void smoothOpenMenu(int duration) { |
||||||
|
if (mSwipeCurrentHorizontal != null) { |
||||||
|
mSwipeCurrentHorizontal.autoOpenMenu(mScroller, getScrollX(), duration); |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothCloseMenu() { |
||||||
|
smoothCloseMenu(mScrollerDuration); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothCloseLeftMenu() { |
||||||
|
if (mSwipeLeftHorizontal != null) { |
||||||
|
mSwipeCurrentHorizontal = mSwipeLeftHorizontal; |
||||||
|
smoothCloseMenu(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothCloseRightMenu() { |
||||||
|
if (mSwipeRightHorizontal != null) { |
||||||
|
mSwipeCurrentHorizontal = mSwipeRightHorizontal; |
||||||
|
smoothCloseMenu(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void smoothCloseMenu(int duration) { |
||||||
|
if (mSwipeCurrentHorizontal != null) { |
||||||
|
mSwipeCurrentHorizontal.autoCloseMenu(mScroller, getScrollX(), duration); |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onLayout(boolean changed, int l, int t, int r, int b) { |
||||||
|
int contentViewHeight; |
||||||
|
if (mContentView != null) { |
||||||
|
int contentViewWidth = mContentView.getMeasuredWidthAndState(); |
||||||
|
contentViewHeight = mContentView.getMeasuredHeightAndState(); |
||||||
|
LayoutParams lp = (LayoutParams) mContentView.getLayoutParams(); |
||||||
|
int start = getPaddingLeft(); |
||||||
|
int top = getPaddingTop() + lp.topMargin; |
||||||
|
mContentView.layout(start, top, start + contentViewWidth, top + contentViewHeight); |
||||||
|
} |
||||||
|
|
||||||
|
if (mSwipeLeftHorizontal != null) { |
||||||
|
View leftMenu = mSwipeLeftHorizontal.getMenuView(); |
||||||
|
int menuViewWidth = leftMenu.getMeasuredWidthAndState(); |
||||||
|
int menuViewHeight = leftMenu.getMeasuredHeightAndState(); |
||||||
|
LayoutParams lp = (LayoutParams) leftMenu.getLayoutParams(); |
||||||
|
int top = getPaddingTop() + lp.topMargin; |
||||||
|
leftMenu.layout(-menuViewWidth, top, 0, top + menuViewHeight); |
||||||
|
} |
||||||
|
|
||||||
|
if (mSwipeRightHorizontal != null) { |
||||||
|
View rightMenu = mSwipeRightHorizontal.getMenuView(); |
||||||
|
int menuViewWidth = rightMenu.getMeasuredWidthAndState(); |
||||||
|
int menuViewHeight = rightMenu.getMeasuredHeightAndState(); |
||||||
|
LayoutParams lp = (LayoutParams) rightMenu.getLayoutParams(); |
||||||
|
int top = getPaddingTop() + lp.topMargin; |
||||||
|
|
||||||
|
int parentViewWidth = getMeasuredWidthAndState(); |
||||||
|
rightMenu.layout(parentViewWidth, top, parentViewWidth + menuViewWidth, top + menuViewHeight); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.content.res.ColorStateList; |
||||||
|
import android.graphics.Typeface; |
||||||
|
import android.text.TextUtils; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.util.TypedValue; |
||||||
|
import android.view.Gravity; |
||||||
|
import android.view.View; |
||||||
|
import android.widget.ImageView; |
||||||
|
import android.widget.LinearLayout; |
||||||
|
import android.widget.TextView; |
||||||
|
|
||||||
|
import androidx.core.view.ViewCompat; |
||||||
|
import androidx.core.widget.TextViewCompat; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/26. |
||||||
|
*/ |
||||||
|
public class SwipeMenuView extends LinearLayout implements View.OnClickListener { |
||||||
|
|
||||||
|
private RecyclerView.ViewHolder mViewHolder; |
||||||
|
private OnItemMenuClickListener mItemClickListener; |
||||||
|
|
||||||
|
public SwipeMenuView(Context context) { |
||||||
|
this(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuView(Context context, AttributeSet attrs) { |
||||||
|
this(context, attrs, 0); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeMenuView(Context context, AttributeSet attrs, int defStyleAttr) { |
||||||
|
super(context, attrs, defStyleAttr); |
||||||
|
setGravity(Gravity.CENTER_VERTICAL); |
||||||
|
} |
||||||
|
|
||||||
|
public void createMenu(RecyclerView.ViewHolder viewHolder, SwipeMenu swipeMenu, Controller controller, |
||||||
|
int direction, OnItemMenuClickListener itemClickListener) { |
||||||
|
removeAllViews(); |
||||||
|
|
||||||
|
this.mViewHolder = viewHolder; |
||||||
|
this.mItemClickListener = itemClickListener; |
||||||
|
|
||||||
|
List<SwipeMenuItem> items = swipeMenu.getMenuItems(); |
||||||
|
for (int i = 0; i < items.size(); i++) { |
||||||
|
SwipeMenuItem item = items.get(i); |
||||||
|
|
||||||
|
LayoutParams params = new LayoutParams(item.getWidth(), item.getHeight()); |
||||||
|
params.weight = item.getWeight(); |
||||||
|
LinearLayout parent = new LinearLayout(getContext()); |
||||||
|
parent.setId(i); |
||||||
|
parent.setGravity(Gravity.CENTER); |
||||||
|
parent.setOrientation(VERTICAL); |
||||||
|
parent.setLayoutParams(params); |
||||||
|
ViewCompat.setBackground(parent, item.getBackground()); |
||||||
|
parent.setOnClickListener(this); |
||||||
|
addView(parent); |
||||||
|
|
||||||
|
SwipeMenuBridge menuBridge = new SwipeMenuBridge(controller, direction, i); |
||||||
|
parent.setTag(menuBridge); |
||||||
|
|
||||||
|
if (item.getImage() != null) { |
||||||
|
ImageView iv = createIcon(item); |
||||||
|
parent.addView(iv); |
||||||
|
} |
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(item.getText())) { |
||||||
|
TextView tv = createTitle(item); |
||||||
|
parent.addView(tv); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onClick(View v) { |
||||||
|
if (mItemClickListener != null) { |
||||||
|
mItemClickListener.onItemClick((SwipeMenuBridge)v.getTag(), mViewHolder.getAdapterPosition()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private ImageView createIcon(SwipeMenuItem item) { |
||||||
|
ImageView imageView = new ImageView(getContext()); |
||||||
|
imageView.setImageDrawable(item.getImage()); |
||||||
|
return imageView; |
||||||
|
} |
||||||
|
|
||||||
|
private TextView createTitle(SwipeMenuItem item) { |
||||||
|
TextView textView = new TextView(getContext()); |
||||||
|
textView.setText(item.getText()); |
||||||
|
textView.setGravity(Gravity.CENTER); |
||||||
|
int textSize = item.getTextSize(); |
||||||
|
if (textSize > 0) textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize); |
||||||
|
ColorStateList textColor = item.getTitleColor(); |
||||||
|
if (textColor != null) textView.setTextColor(textColor); |
||||||
|
int textAppearance = item.getTextAppearance(); |
||||||
|
if (textAppearance != 0) TextViewCompat.setTextAppearance(textView, textAppearance); |
||||||
|
Typeface typeface = item.getTextTypeface(); |
||||||
|
if (typeface != null) textView.setTypeface(typeface); |
||||||
|
return textView; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,864 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewConfiguration; |
||||||
|
import android.view.ViewGroup; |
||||||
|
import android.view.ViewParent; |
||||||
|
|
||||||
|
import androidx.annotation.IntDef; |
||||||
|
import androidx.recyclerview.widget.GridLayoutManager; |
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager; |
||||||
|
|
||||||
|
import com.project.survey.widget.swiperecyclerview.touch.DefaultItemTouchHelper; |
||||||
|
import com.project.survey.widget.swiperecyclerview.touch.OnItemMoveListener; |
||||||
|
import com.project.survey.widget.swiperecyclerview.touch.OnItemMovementListener; |
||||||
|
import com.project.survey.widget.swiperecyclerview.touch.OnItemStateChangedListener; |
||||||
|
import com.project.survey.widget.swiperecyclerview.widget.DefaultLoadMoreView; |
||||||
|
|
||||||
|
import java.lang.annotation.Retention; |
||||||
|
import java.lang.annotation.RetentionPolicy; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/7/27. |
||||||
|
*/ |
||||||
|
public class SwipeRecyclerView extends RecyclerView { |
||||||
|
|
||||||
|
/** |
||||||
|
* Left menu. |
||||||
|
*/ |
||||||
|
public static final int LEFT_DIRECTION = 1; |
||||||
|
/** |
||||||
|
* Right menu. |
||||||
|
*/ |
||||||
|
public static final int RIGHT_DIRECTION = -1; |
||||||
|
|
||||||
|
@IntDef({LEFT_DIRECTION, RIGHT_DIRECTION}) |
||||||
|
@Retention(RetentionPolicy.SOURCE) |
||||||
|
public @interface DirectionMode { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Invalid position. |
||||||
|
*/ |
||||||
|
private static final int INVALID_POSITION = -1; |
||||||
|
|
||||||
|
protected int mScaleTouchSlop; |
||||||
|
protected SwipeMenuLayout mOldSwipedLayout; |
||||||
|
protected int mOldTouchedPosition = INVALID_POSITION; |
||||||
|
|
||||||
|
private int mDownX; |
||||||
|
private int mDownY; |
||||||
|
|
||||||
|
private boolean allowSwipeDelete; |
||||||
|
|
||||||
|
private DefaultItemTouchHelper mItemTouchHelper; |
||||||
|
|
||||||
|
private SwipeMenuCreator mSwipeMenuCreator; |
||||||
|
private OnItemMenuClickListener mOnItemMenuClickListener; |
||||||
|
private OnItemClickListener mOnItemClickListener; |
||||||
|
private OnItemLongClickListener mOnItemLongClickListener; |
||||||
|
private AdapterWrapper mAdapterWrapper; |
||||||
|
|
||||||
|
private boolean mSwipeItemMenuEnable = true; |
||||||
|
private List<Integer> mDisableSwipeItemMenuList = new ArrayList<>(); |
||||||
|
|
||||||
|
public SwipeRecyclerView(Context context) { |
||||||
|
this(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeRecyclerView(Context context, AttributeSet attrs) { |
||||||
|
this(context, attrs, 0); |
||||||
|
} |
||||||
|
|
||||||
|
public SwipeRecyclerView(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
mScaleTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); |
||||||
|
} |
||||||
|
|
||||||
|
private void initializeItemTouchHelper() { |
||||||
|
if (mItemTouchHelper == null) { |
||||||
|
mItemTouchHelper = new DefaultItemTouchHelper(); |
||||||
|
mItemTouchHelper.attachToRecyclerView(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set OnItemMoveListener. |
||||||
|
* |
||||||
|
* @param listener {@link OnItemMoveListener}. |
||||||
|
*/ |
||||||
|
public void setOnItemMoveListener(OnItemMoveListener listener) { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
this.mItemTouchHelper.setOnItemMoveListener(listener); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set OnItemMovementListener. |
||||||
|
* |
||||||
|
* @param listener {@link OnItemMovementListener}. |
||||||
|
*/ |
||||||
|
public void setOnItemMovementListener(OnItemMovementListener listener) { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
this.mItemTouchHelper.setOnItemMovementListener(listener); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set OnItemStateChangedListener. |
||||||
|
* |
||||||
|
* @param listener {@link OnItemStateChangedListener}. |
||||||
|
*/ |
||||||
|
public void setOnItemStateChangedListener(OnItemStateChangedListener listener) { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
this.mItemTouchHelper.setOnItemStateChangedListener(listener); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the item menu to enable status. |
||||||
|
* |
||||||
|
* @param enabled true means available, otherwise not available; default is true. |
||||||
|
*/ |
||||||
|
public void setSwipeItemMenuEnabled(boolean enabled) { |
||||||
|
this.mSwipeItemMenuEnable = enabled; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* True means available, otherwise not available; default is true. |
||||||
|
*/ |
||||||
|
public boolean isSwipeItemMenuEnabled() { |
||||||
|
return mSwipeItemMenuEnable; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the item menu to enable status. |
||||||
|
* |
||||||
|
* @param position the position of the item. |
||||||
|
* @param enabled true means available, otherwise not available; default is true. |
||||||
|
*/ |
||||||
|
public void setSwipeItemMenuEnabled(int position, boolean enabled) { |
||||||
|
if (enabled) { |
||||||
|
if (mDisableSwipeItemMenuList.contains(position)) { |
||||||
|
mDisableSwipeItemMenuList.remove(Integer.valueOf(position)); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (!mDisableSwipeItemMenuList.contains(position)) { |
||||||
|
mDisableSwipeItemMenuList.add(position); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* True means available, otherwise not available; default is true. |
||||||
|
* |
||||||
|
* @param position the position of the item. |
||||||
|
*/ |
||||||
|
public boolean isSwipeItemMenuEnabled(int position) { |
||||||
|
return !mDisableSwipeItemMenuList.contains(position); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set can long press drag. |
||||||
|
* |
||||||
|
* @param canDrag drag true, otherwise is can't. |
||||||
|
*/ |
||||||
|
public void setLongPressDragEnabled(boolean canDrag) { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
this.mItemTouchHelper.setLongPressDragEnabled(canDrag); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get can long press drag. |
||||||
|
* |
||||||
|
* @return drag true, otherwise is can't. |
||||||
|
*/ |
||||||
|
public boolean isLongPressDragEnabled() { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
return this.mItemTouchHelper.isLongPressDragEnabled(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Set can swipe delete. |
||||||
|
* |
||||||
|
* @param canSwipe swipe true, otherwise is can't. |
||||||
|
*/ |
||||||
|
public void setItemViewSwipeEnabled(boolean canSwipe) { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
allowSwipeDelete = canSwipe; // swipe and menu conflict.
|
||||||
|
this.mItemTouchHelper.setItemViewSwipeEnabled(canSwipe); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get can long press swipe. |
||||||
|
* |
||||||
|
* @return swipe true, otherwise is can't. |
||||||
|
*/ |
||||||
|
public boolean isItemViewSwipeEnabled() { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
return this.mItemTouchHelper.isItemViewSwipeEnabled(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Start drag a item. |
||||||
|
* |
||||||
|
* @param viewHolder the ViewHolder to start dragging. It must be a direct child of RecyclerView. |
||||||
|
*/ |
||||||
|
public void startDrag(ViewHolder viewHolder) { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
this.mItemTouchHelper.startDrag(viewHolder); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Star swipe a item. |
||||||
|
* |
||||||
|
* @param viewHolder the ViewHolder to start swiping. It must be a direct child of RecyclerView. |
||||||
|
*/ |
||||||
|
public void startSwipe(ViewHolder viewHolder) { |
||||||
|
initializeItemTouchHelper(); |
||||||
|
this.mItemTouchHelper.startSwipe(viewHolder); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Check the Adapter and throw an exception if it already exists. |
||||||
|
*/ |
||||||
|
private void checkAdapterExist(String message) { |
||||||
|
if (mAdapterWrapper != null) throw new IllegalStateException(message); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set item click listener. |
||||||
|
*/ |
||||||
|
public void setOnItemClickListener(OnItemClickListener listener) { |
||||||
|
if (listener == null) return; |
||||||
|
checkAdapterExist("Cannot set item click listener, setAdapter has already been called."); |
||||||
|
this.mOnItemClickListener = new ItemClickListener(this, listener); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ItemClickListener implements OnItemClickListener { |
||||||
|
|
||||||
|
private SwipeRecyclerView mRecyclerView; |
||||||
|
private OnItemClickListener mListener; |
||||||
|
|
||||||
|
public ItemClickListener(SwipeRecyclerView recyclerView, OnItemClickListener listener) { |
||||||
|
this.mRecyclerView = recyclerView; |
||||||
|
this.mListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemClick(View itemView, int position) { |
||||||
|
position -= mRecyclerView.getHeaderCount(); |
||||||
|
if (position >= 0) mListener.onItemClick(itemView, position); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set item click listener. |
||||||
|
*/ |
||||||
|
public void setOnItemLongClickListener(OnItemLongClickListener listener) { |
||||||
|
if (listener == null) return; |
||||||
|
checkAdapterExist("Cannot set item long click listener, setAdapter has already been called."); |
||||||
|
this.mOnItemLongClickListener = new ItemLongClickListener(this, listener); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ItemLongClickListener implements OnItemLongClickListener { |
||||||
|
|
||||||
|
private SwipeRecyclerView mRecyclerView; |
||||||
|
private OnItemLongClickListener mListener; |
||||||
|
|
||||||
|
public ItemLongClickListener(SwipeRecyclerView recyclerView, OnItemLongClickListener listener) { |
||||||
|
this.mRecyclerView = recyclerView; |
||||||
|
this.mListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemLongClick(View itemView, int position) { |
||||||
|
position -= mRecyclerView.getHeaderCount(); |
||||||
|
if (position >= 0) mListener.onItemLongClick(itemView, position); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set to create menu listener. |
||||||
|
*/ |
||||||
|
public void setSwipeMenuCreator(SwipeMenuCreator menuCreator) { |
||||||
|
if (menuCreator == null) return; |
||||||
|
checkAdapterExist("Cannot set menu creator, setAdapter has already been called."); |
||||||
|
this.mSwipeMenuCreator = menuCreator; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set to click menu listener. |
||||||
|
*/ |
||||||
|
public void setOnItemMenuClickListener(OnItemMenuClickListener listener) { |
||||||
|
if (listener == null) return; |
||||||
|
checkAdapterExist("Cannot set menu item click listener, setAdapter has already been called."); |
||||||
|
this.mOnItemMenuClickListener = new ItemMenuClickListener(this, listener); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ItemMenuClickListener implements OnItemMenuClickListener { |
||||||
|
|
||||||
|
private SwipeRecyclerView mRecyclerView; |
||||||
|
private OnItemMenuClickListener mListener; |
||||||
|
|
||||||
|
public ItemMenuClickListener(SwipeRecyclerView recyclerView, OnItemMenuClickListener listener) { |
||||||
|
this.mRecyclerView = recyclerView; |
||||||
|
this.mListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemClick(SwipeMenuBridge menuBridge, int position) { |
||||||
|
position -= mRecyclerView.getHeaderCount(); |
||||||
|
if (position >= 0) { |
||||||
|
mListener.onItemClick(menuBridge, position); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setLayoutManager(LayoutManager layoutManager) { |
||||||
|
if (layoutManager instanceof GridLayoutManager) { |
||||||
|
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; |
||||||
|
final GridLayoutManager.SpanSizeLookup spanSizeLookupHolder = gridLayoutManager.getSpanSizeLookup(); |
||||||
|
|
||||||
|
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { |
||||||
|
@Override |
||||||
|
public int getSpanSize(int position) { |
||||||
|
if (mAdapterWrapper.isHeader(position) || mAdapterWrapper.isFooter(position)) { |
||||||
|
return gridLayoutManager.getSpanCount(); |
||||||
|
} |
||||||
|
if (spanSizeLookupHolder != null) { |
||||||
|
return spanSizeLookupHolder.getSpanSize(position - getHeaderCount()); |
||||||
|
} |
||||||
|
return 1; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
super.setLayoutManager(layoutManager); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the original adapter. |
||||||
|
*/ |
||||||
|
public Adapter getOriginAdapter() { |
||||||
|
if (mAdapterWrapper == null) return null; |
||||||
|
return mAdapterWrapper.getOriginAdapter(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setAdapter(Adapter adapter) { |
||||||
|
if (mAdapterWrapper != null) { |
||||||
|
mAdapterWrapper.getOriginAdapter().unregisterAdapterDataObserver(mAdapterDataObserver); |
||||||
|
} |
||||||
|
|
||||||
|
if (adapter == null) { |
||||||
|
mAdapterWrapper = null; |
||||||
|
} else { |
||||||
|
adapter.registerAdapterDataObserver(mAdapterDataObserver); |
||||||
|
|
||||||
|
mAdapterWrapper = new AdapterWrapper(getContext(), adapter); |
||||||
|
mAdapterWrapper.setOnItemClickListener(mOnItemClickListener); |
||||||
|
mAdapterWrapper.setOnItemLongClickListener(mOnItemLongClickListener); |
||||||
|
mAdapterWrapper.setSwipeMenuCreator(mSwipeMenuCreator); |
||||||
|
mAdapterWrapper.setOnItemMenuClickListener(mOnItemMenuClickListener); |
||||||
|
|
||||||
|
if (mHeaderViewList.size() > 0) { |
||||||
|
for (View view : mHeaderViewList) { |
||||||
|
mAdapterWrapper.addHeaderView(view); |
||||||
|
} |
||||||
|
} |
||||||
|
if (mFooterViewList.size() > 0) { |
||||||
|
for (View view : mFooterViewList) { |
||||||
|
mAdapterWrapper.addFooterView(view); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
super.setAdapter(mAdapterWrapper); |
||||||
|
} |
||||||
|
|
||||||
|
private AdapterDataObserver mAdapterDataObserver = new AdapterDataObserver() { |
||||||
|
@Override |
||||||
|
public void onChanged() { |
||||||
|
mAdapterWrapper.notifyDataSetChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemRangeChanged(int positionStart, int itemCount) { |
||||||
|
positionStart += getHeaderCount(); |
||||||
|
mAdapterWrapper.notifyItemRangeChanged(positionStart, itemCount); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { |
||||||
|
positionStart += getHeaderCount(); |
||||||
|
mAdapterWrapper.notifyItemRangeChanged(positionStart, itemCount, payload); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemRangeInserted(int positionStart, int itemCount) { |
||||||
|
positionStart += getHeaderCount(); |
||||||
|
mAdapterWrapper.notifyItemRangeInserted(positionStart, itemCount); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemRangeRemoved(int positionStart, int itemCount) { |
||||||
|
positionStart += getHeaderCount(); |
||||||
|
mAdapterWrapper.notifyItemRangeRemoved(positionStart, itemCount); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { |
||||||
|
fromPosition += getHeaderCount(); |
||||||
|
toPosition += getHeaderCount(); |
||||||
|
mAdapterWrapper.notifyItemMoved(fromPosition, toPosition); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private List<View> mHeaderViewList = new ArrayList<>(); |
||||||
|
private List<View> mFooterViewList = new ArrayList<>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Add view at the headers. |
||||||
|
*/ |
||||||
|
public void addHeaderView(View view) { |
||||||
|
mHeaderViewList.add(view); |
||||||
|
if (mAdapterWrapper != null) { |
||||||
|
mAdapterWrapper.addHeaderViewAndNotify(view); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Remove view from header. |
||||||
|
*/ |
||||||
|
public void removeHeaderView(View view) { |
||||||
|
mHeaderViewList.remove(view); |
||||||
|
if (mAdapterWrapper != null) { |
||||||
|
mAdapterWrapper.removeHeaderViewAndNotify(view); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add view at the footer. |
||||||
|
*/ |
||||||
|
public void addFooterView(View view) { |
||||||
|
mFooterViewList.add(view); |
||||||
|
if (mAdapterWrapper != null) { |
||||||
|
mAdapterWrapper.addFooterViewAndNotify(view); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void removeFooterView(View view) { |
||||||
|
mFooterViewList.remove(view); |
||||||
|
if (mAdapterWrapper != null) { |
||||||
|
mAdapterWrapper.removeFooterViewAndNotify(view); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get size of headers. |
||||||
|
*/ |
||||||
|
public int getHeaderCount() { |
||||||
|
if (mAdapterWrapper == null) return 0; |
||||||
|
return mAdapterWrapper.getHeaderCount(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get size of footer. |
||||||
|
*/ |
||||||
|
public int getFooterCount() { |
||||||
|
if (mAdapterWrapper == null) return 0; |
||||||
|
return mAdapterWrapper.getFooterCount(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get ViewType of item. |
||||||
|
*/ |
||||||
|
public int getItemViewType(int position) { |
||||||
|
if (mAdapterWrapper == null) return 0; |
||||||
|
return mAdapterWrapper.getItemViewType(position); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* open menu on left. |
||||||
|
* |
||||||
|
* @param position position. |
||||||
|
*/ |
||||||
|
public void smoothOpenLeftMenu(int position) { |
||||||
|
smoothOpenMenu(position, LEFT_DIRECTION, SwipeMenuLayout.DEFAULT_SCROLLER_DURATION); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* open menu on left. |
||||||
|
* |
||||||
|
* @param position position. |
||||||
|
* @param duration time millis. |
||||||
|
*/ |
||||||
|
public void smoothOpenLeftMenu(int position, int duration) { |
||||||
|
smoothOpenMenu(position, LEFT_DIRECTION, duration); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* open menu on right. |
||||||
|
* |
||||||
|
* @param position position. |
||||||
|
*/ |
||||||
|
public void smoothOpenRightMenu(int position) { |
||||||
|
smoothOpenMenu(position, RIGHT_DIRECTION, SwipeMenuLayout.DEFAULT_SCROLLER_DURATION); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* open menu on right. |
||||||
|
* |
||||||
|
* @param position position. |
||||||
|
* @param duration time millis. |
||||||
|
*/ |
||||||
|
public void smoothOpenRightMenu(int position, int duration) { |
||||||
|
smoothOpenMenu(position, RIGHT_DIRECTION, duration); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* open menu. |
||||||
|
* |
||||||
|
* @param position position. |
||||||
|
* @param direction use {@link #LEFT_DIRECTION}, {@link #RIGHT_DIRECTION}. |
||||||
|
* @param duration time millis. |
||||||
|
*/ |
||||||
|
public void smoothOpenMenu(int position, @DirectionMode int direction, int duration) { |
||||||
|
if (mOldSwipedLayout != null) { |
||||||
|
if (mOldSwipedLayout.isMenuOpen()) { |
||||||
|
mOldSwipedLayout.smoothCloseMenu(); |
||||||
|
} |
||||||
|
} |
||||||
|
position += getHeaderCount(); |
||||||
|
ViewHolder vh = findViewHolderForAdapterPosition(position); |
||||||
|
if (vh != null) { |
||||||
|
View itemView = getSwipeMenuView(vh.itemView); |
||||||
|
if (itemView instanceof SwipeMenuLayout) { |
||||||
|
mOldSwipedLayout = (SwipeMenuLayout) itemView; |
||||||
|
if (direction == RIGHT_DIRECTION) { |
||||||
|
mOldTouchedPosition = position; |
||||||
|
mOldSwipedLayout.smoothOpenRightMenu(duration); |
||||||
|
} else if (direction == LEFT_DIRECTION) { |
||||||
|
mOldTouchedPosition = position; |
||||||
|
mOldSwipedLayout.smoothOpenLeftMenu(duration); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Close menu. |
||||||
|
*/ |
||||||
|
public void smoothCloseMenu() { |
||||||
|
if (mOldSwipedLayout != null && mOldSwipedLayout.isMenuOpen()) { |
||||||
|
mOldSwipedLayout.smoothCloseMenu(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onInterceptTouchEvent(MotionEvent e) { |
||||||
|
boolean isIntercepted = super.onInterceptTouchEvent(e); |
||||||
|
if (allowSwipeDelete || mSwipeMenuCreator == null) { |
||||||
|
return isIntercepted; |
||||||
|
} else { |
||||||
|
if (e.getPointerCount() > 1) return true; |
||||||
|
int action = e.getAction(); |
||||||
|
int x = (int) e.getX(); |
||||||
|
int y = (int) e.getY(); |
||||||
|
|
||||||
|
int touchPosition = getChildAdapterPosition(findChildViewUnder(x, y)); |
||||||
|
ViewHolder touchVH = findViewHolderForAdapterPosition(touchPosition); |
||||||
|
SwipeMenuLayout touchView = null; |
||||||
|
if (touchVH != null) { |
||||||
|
View itemView = getSwipeMenuView(touchVH.itemView); |
||||||
|
if (itemView instanceof SwipeMenuLayout) { |
||||||
|
touchView = (SwipeMenuLayout) itemView; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
boolean touchMenuEnable = mSwipeItemMenuEnable && !mDisableSwipeItemMenuList.contains(touchPosition); |
||||||
|
if (touchView != null) { |
||||||
|
touchView.setSwipeEnable(touchMenuEnable); |
||||||
|
} |
||||||
|
if (!touchMenuEnable) return isIntercepted; |
||||||
|
|
||||||
|
switch (action) { |
||||||
|
case MotionEvent.ACTION_DOWN: { |
||||||
|
mDownX = x; |
||||||
|
mDownY = y; |
||||||
|
|
||||||
|
isIntercepted = false; |
||||||
|
if (touchPosition != mOldTouchedPosition && mOldSwipedLayout != null && |
||||||
|
mOldSwipedLayout.isMenuOpen()) { |
||||||
|
mOldSwipedLayout.smoothCloseMenu(); |
||||||
|
isIntercepted = true; |
||||||
|
} |
||||||
|
|
||||||
|
if (isIntercepted) { |
||||||
|
mOldSwipedLayout = null; |
||||||
|
mOldTouchedPosition = INVALID_POSITION; |
||||||
|
} else if (touchView != null) { |
||||||
|
mOldSwipedLayout = touchView; |
||||||
|
mOldTouchedPosition = touchPosition; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
// They are sensitive to retain sliding and inertia.
|
||||||
|
case MotionEvent.ACTION_MOVE: { |
||||||
|
isIntercepted = handleUnDown(x, y, isIntercepted); |
||||||
|
if (mOldSwipedLayout == null) break; |
||||||
|
ViewParent viewParent = getParent(); |
||||||
|
if (viewParent == null) break; |
||||||
|
|
||||||
|
int disX = mDownX - x; |
||||||
|
// 向左滑,显示右侧菜单,或者关闭左侧菜单。
|
||||||
|
boolean showRightCloseLeft = disX > 0 && |
||||||
|
(mOldSwipedLayout.hasRightMenu() || mOldSwipedLayout.isLeftCompleteOpen()); |
||||||
|
// 向右滑,显示左侧菜单,或者关闭右侧菜单。
|
||||||
|
boolean showLeftCloseRight = disX < 0 && |
||||||
|
(mOldSwipedLayout.hasLeftMenu() || mOldSwipedLayout.isRightCompleteOpen()); |
||||||
|
viewParent.requestDisallowInterceptTouchEvent(showRightCloseLeft || showLeftCloseRight); |
||||||
|
} |
||||||
|
case MotionEvent.ACTION_UP: |
||||||
|
case MotionEvent.ACTION_CANCEL: { |
||||||
|
isIntercepted = handleUnDown(x, y, isIntercepted); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return isIntercepted; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean handleUnDown(int x, int y, boolean defaultValue) { |
||||||
|
int disX = mDownX - x; |
||||||
|
int disY = mDownY - y; |
||||||
|
|
||||||
|
// swipe
|
||||||
|
if (Math.abs(disX) > mScaleTouchSlop && Math.abs(disX) > Math.abs(disY)) return false; |
||||||
|
// click
|
||||||
|
if (Math.abs(disY) < mScaleTouchSlop && Math.abs(disX) < mScaleTouchSlop) return false; |
||||||
|
return defaultValue; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onTouchEvent(MotionEvent e) { |
||||||
|
int action = e.getAction(); |
||||||
|
switch (action) { |
||||||
|
case MotionEvent.ACTION_DOWN: |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_MOVE: |
||||||
|
if (mOldSwipedLayout != null && mOldSwipedLayout.isMenuOpen()) { |
||||||
|
mOldSwipedLayout.smoothCloseMenu(); |
||||||
|
} |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_UP: |
||||||
|
break; |
||||||
|
case MotionEvent.ACTION_CANCEL: |
||||||
|
break; |
||||||
|
} |
||||||
|
return super.onTouchEvent(e); |
||||||
|
} |
||||||
|
|
||||||
|
private View getSwipeMenuView(View itemView) { |
||||||
|
if (itemView instanceof SwipeMenuLayout) return itemView; |
||||||
|
List<View> unvisited = new ArrayList<>(); |
||||||
|
unvisited.add(itemView); |
||||||
|
while (!unvisited.isEmpty()) { |
||||||
|
View child = unvisited.remove(0); |
||||||
|
if (!(child instanceof ViewGroup)) { // view
|
||||||
|
continue; |
||||||
|
} |
||||||
|
if (child instanceof SwipeMenuLayout) return child; |
||||||
|
ViewGroup group = (ViewGroup) child; |
||||||
|
final int childCount = group.getChildCount(); |
||||||
|
for (int i = 0; i < childCount; i++) unvisited.add(group.getChildAt(i)); |
||||||
|
} |
||||||
|
return itemView; |
||||||
|
} |
||||||
|
|
||||||
|
private int mScrollState = -1; |
||||||
|
|
||||||
|
private boolean isLoadMore = false; |
||||||
|
private boolean isAutoLoadMore = true; |
||||||
|
private boolean isLoadError = false; |
||||||
|
|
||||||
|
private boolean mDataEmpty = true; |
||||||
|
private boolean mHasMore = false; |
||||||
|
|
||||||
|
private LoadMoreView mLoadMoreView; |
||||||
|
private LoadMoreListener mLoadMoreListener; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onScrollStateChanged(int state) { |
||||||
|
this.mScrollState = state; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onScrolled(int dx, int dy) { |
||||||
|
LayoutManager layoutManager = getLayoutManager(); |
||||||
|
if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; |
||||||
|
|
||||||
|
int itemCount = layoutManager.getItemCount(); |
||||||
|
if (itemCount <= 0) return; |
||||||
|
|
||||||
|
int lastVisiblePosition = linearLayoutManager.findLastVisibleItemPosition(); |
||||||
|
|
||||||
|
if (itemCount == lastVisiblePosition + 1 && |
||||||
|
(mScrollState == SCROLL_STATE_DRAGGING || mScrollState == SCROLL_STATE_SETTLING)) { |
||||||
|
dispatchLoadMore(); |
||||||
|
} |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager; |
||||||
|
|
||||||
|
int itemCount = layoutManager.getItemCount(); |
||||||
|
if (itemCount <= 0) return; |
||||||
|
|
||||||
|
int[] lastVisiblePositionArray = staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(null); |
||||||
|
int lastVisiblePosition = lastVisiblePositionArray[lastVisiblePositionArray.length - 1]; |
||||||
|
|
||||||
|
if (itemCount == lastVisiblePosition + 1 && |
||||||
|
(mScrollState == SCROLL_STATE_DRAGGING || mScrollState == SCROLL_STATE_SETTLING)) { |
||||||
|
dispatchLoadMore(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void dispatchLoadMore() { |
||||||
|
if (isLoadError) return; |
||||||
|
|
||||||
|
if (!isAutoLoadMore) { |
||||||
|
if (mLoadMoreView != null) mLoadMoreView.onWaitToLoadMore(mLoadMoreListener); |
||||||
|
} else { |
||||||
|
if (isLoadMore || mDataEmpty || !mHasMore) return; |
||||||
|
|
||||||
|
isLoadMore = true; |
||||||
|
|
||||||
|
if (mLoadMoreView != null) mLoadMoreView.onLoading(); |
||||||
|
|
||||||
|
if (mLoadMoreListener != null) mLoadMoreListener.onLoadMore(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Use the default to load more View. |
||||||
|
*/ |
||||||
|
public void useDefaultLoadMore() { |
||||||
|
DefaultLoadMoreView defaultLoadMoreView = new DefaultLoadMoreView(getContext()); |
||||||
|
addFooterView(defaultLoadMoreView); |
||||||
|
setLoadMoreView(defaultLoadMoreView); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Load more view. |
||||||
|
*/ |
||||||
|
public void setLoadMoreView(LoadMoreView view) { |
||||||
|
mLoadMoreView = view; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Load more listener. |
||||||
|
*/ |
||||||
|
public void setLoadMoreListener(LoadMoreListener listener) { |
||||||
|
mLoadMoreListener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Automatically load more automatically. |
||||||
|
* <p> |
||||||
|
* Non-auto-loading mode, you can to click on the item to load. |
||||||
|
* </p> |
||||||
|
* |
||||||
|
* @param autoLoadMore you can use false. |
||||||
|
* @see LoadMoreView#onWaitToLoadMore(LoadMoreListener) |
||||||
|
*/ |
||||||
|
public void setAutoLoadMore(boolean autoLoadMore) { |
||||||
|
isAutoLoadMore = autoLoadMore; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Load more done. |
||||||
|
* |
||||||
|
* @param dataEmpty data is empty ? |
||||||
|
* @param hasMore has more data ? |
||||||
|
*/ |
||||||
|
public final void loadMoreFinish(boolean dataEmpty, boolean hasMore) { |
||||||
|
isLoadMore = false; |
||||||
|
isLoadError = false; |
||||||
|
|
||||||
|
mDataEmpty = dataEmpty; |
||||||
|
mHasMore = hasMore; |
||||||
|
|
||||||
|
if (mLoadMoreView != null) { |
||||||
|
mLoadMoreView.onLoadFinish(dataEmpty, hasMore); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when data is loaded incorrectly. |
||||||
|
* |
||||||
|
* @param errorCode Error code, will be passed to the LoadView, you can according to it to customize the prompt |
||||||
|
* information. |
||||||
|
* @param errorMessage Error message. |
||||||
|
*/ |
||||||
|
public void loadMoreError(int errorCode, String errorMessage) { |
||||||
|
isLoadMore = false; |
||||||
|
isLoadError = true; |
||||||
|
|
||||||
|
if (mLoadMoreView != null) { |
||||||
|
mLoadMoreView.onLoadError(errorCode, errorMessage); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public interface LoadMoreView { |
||||||
|
|
||||||
|
/** |
||||||
|
* Show progress. |
||||||
|
*/ |
||||||
|
void onLoading(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Load finish, handle result. |
||||||
|
*/ |
||||||
|
void onLoadFinish(boolean dataEmpty, boolean hasMore); |
||||||
|
|
||||||
|
/** |
||||||
|
* Non-auto-loading mode, you can to click on the item to load. |
||||||
|
*/ |
||||||
|
void onWaitToLoadMore(LoadMoreListener loadMoreListener); |
||||||
|
|
||||||
|
/** |
||||||
|
* Load error. |
||||||
|
*/ |
||||||
|
void onLoadError(int errorCode, String errorMessage); |
||||||
|
} |
||||||
|
|
||||||
|
public interface LoadMoreListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* More data should be requested. |
||||||
|
*/ |
||||||
|
void onLoadMore(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,132 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.touch; |
||||||
|
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yolanda on 2016/4/19. |
||||||
|
*/ |
||||||
|
public class DefaultItemTouchHelper extends ItemTouchHelper { |
||||||
|
|
||||||
|
private ItemTouchHelperCallback mItemTouchHelperCallback; |
||||||
|
|
||||||
|
/** |
||||||
|
* Create default item touch helper. |
||||||
|
*/ |
||||||
|
public DefaultItemTouchHelper() { |
||||||
|
this(new ItemTouchHelperCallback()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param callback the behavior of ItemTouchHelper. |
||||||
|
*/ |
||||||
|
private DefaultItemTouchHelper(ItemTouchHelperCallback callback) { |
||||||
|
super(callback); |
||||||
|
mItemTouchHelperCallback = callback; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set OnItemMoveListener. |
||||||
|
* |
||||||
|
* @param onItemMoveListener {@link OnItemMoveListener}. |
||||||
|
*/ |
||||||
|
public void setOnItemMoveListener(OnItemMoveListener onItemMoveListener) { |
||||||
|
mItemTouchHelperCallback.setOnItemMoveListener(onItemMoveListener); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get OnItemMoveListener. |
||||||
|
* |
||||||
|
* @return {@link OnItemMoveListener}. |
||||||
|
*/ |
||||||
|
public OnItemMoveListener getOnItemMoveListener() { |
||||||
|
return mItemTouchHelperCallback.getOnItemMoveListener(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set OnItemMovementListener. |
||||||
|
* |
||||||
|
* @param onItemMovementListener {@link OnItemMovementListener}. |
||||||
|
*/ |
||||||
|
public void setOnItemMovementListener(OnItemMovementListener onItemMovementListener) { |
||||||
|
mItemTouchHelperCallback.setOnItemMovementListener(onItemMovementListener); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get OnItemMovementListener. |
||||||
|
* |
||||||
|
* @return {@link OnItemMovementListener}. |
||||||
|
*/ |
||||||
|
public OnItemMovementListener getOnItemMovementListener() { |
||||||
|
return mItemTouchHelperCallback.getOnItemMovementListener(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set can long press drag. |
||||||
|
* |
||||||
|
* @param canDrag drag true, otherwise is can't. |
||||||
|
*/ |
||||||
|
public void setLongPressDragEnabled(boolean canDrag) { |
||||||
|
mItemTouchHelperCallback.setLongPressDragEnabled(canDrag); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get can long press drag. |
||||||
|
* |
||||||
|
* @return drag true, otherwise is can't. |
||||||
|
*/ |
||||||
|
public boolean isLongPressDragEnabled() { |
||||||
|
return mItemTouchHelperCallback.isLongPressDragEnabled(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set can long press swipe. |
||||||
|
* |
||||||
|
* @param canSwipe swipe true, otherwise is can't. |
||||||
|
*/ |
||||||
|
public void setItemViewSwipeEnabled(boolean canSwipe) { |
||||||
|
mItemTouchHelperCallback.setItemViewSwipeEnabled(canSwipe); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get can long press swipe. |
||||||
|
* |
||||||
|
* @return swipe true, otherwise is can't. |
||||||
|
*/ |
||||||
|
public boolean isItemViewSwipeEnabled() { |
||||||
|
return this.mItemTouchHelperCallback.isItemViewSwipeEnabled(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set OnItemStateChangedListener. |
||||||
|
* |
||||||
|
* @param onItemStateChangedListener {@link OnItemStateChangedListener}. |
||||||
|
*/ |
||||||
|
public void setOnItemStateChangedListener(OnItemStateChangedListener onItemStateChangedListener) { |
||||||
|
this.mItemTouchHelperCallback.setOnItemStateChangedListener(onItemStateChangedListener); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get OnItemStateChangedListener. |
||||||
|
* |
||||||
|
* @return {@link OnItemStateChangedListener}. |
||||||
|
*/ |
||||||
|
public OnItemStateChangedListener getOnItemStateChangedListener() { |
||||||
|
return this.mItemTouchHelperCallback.getOnItemStateChangedListener(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,174 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.touch; |
||||||
|
|
||||||
|
import android.graphics.Canvas; |
||||||
|
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager; |
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper; |
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yolanda on 2016/4/19. |
||||||
|
*/ |
||||||
|
class ItemTouchHelperCallback extends ItemTouchHelper.Callback { |
||||||
|
|
||||||
|
private OnItemMovementListener onItemMovementListener; |
||||||
|
|
||||||
|
private OnItemMoveListener onItemMoveListener; |
||||||
|
|
||||||
|
private OnItemStateChangedListener onItemStateChangedListener; |
||||||
|
|
||||||
|
private boolean isItemViewSwipeEnabled; |
||||||
|
|
||||||
|
private boolean isLongPressDragEnabled; |
||||||
|
|
||||||
|
public ItemTouchHelperCallback() { |
||||||
|
} |
||||||
|
|
||||||
|
public void setLongPressDragEnabled(boolean canDrag) { |
||||||
|
this.isLongPressDragEnabled = canDrag; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isLongPressDragEnabled() { |
||||||
|
return isLongPressDragEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
public void setItemViewSwipeEnabled(boolean canSwipe) { |
||||||
|
this.isItemViewSwipeEnabled = canSwipe; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isItemViewSwipeEnabled() { |
||||||
|
return isItemViewSwipeEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOnItemMoveListener(OnItemMoveListener onItemMoveListener) { |
||||||
|
this.onItemMoveListener = onItemMoveListener; |
||||||
|
} |
||||||
|
|
||||||
|
public OnItemMoveListener getOnItemMoveListener() { |
||||||
|
return onItemMoveListener; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOnItemMovementListener(OnItemMovementListener onItemMovementListener) { |
||||||
|
this.onItemMovementListener = onItemMovementListener; |
||||||
|
} |
||||||
|
|
||||||
|
public OnItemMovementListener getOnItemMovementListener() { |
||||||
|
return onItemMovementListener; |
||||||
|
} |
||||||
|
|
||||||
|
public void setOnItemStateChangedListener(OnItemStateChangedListener onItemStateChangedListener) { |
||||||
|
this.onItemStateChangedListener = onItemStateChangedListener; |
||||||
|
} |
||||||
|
|
||||||
|
public OnItemStateChangedListener getOnItemStateChangedListener() { |
||||||
|
return onItemStateChangedListener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder targetViewHolder) { |
||||||
|
if (onItemMovementListener != null) { |
||||||
|
int dragFlags = onItemMovementListener.onDragFlags(recyclerView, targetViewHolder); |
||||||
|
int swipeFlags = onItemMovementListener.onSwipeFlags(recyclerView, targetViewHolder); |
||||||
|
return makeMovementFlags(dragFlags, swipeFlags); |
||||||
|
} else { |
||||||
|
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); |
||||||
|
if (layoutManager instanceof GridLayoutManager) { |
||||||
|
LinearLayoutManager linearLayoutManager = (LinearLayoutManager)layoutManager; |
||||||
|
if (linearLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) { |
||||||
|
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | |
||||||
|
ItemTouchHelper.RIGHT; |
||||||
|
int swipeFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; |
||||||
|
return makeMovementFlags(dragFlags, swipeFlags); |
||||||
|
} else { |
||||||
|
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | |
||||||
|
ItemTouchHelper.RIGHT; |
||||||
|
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; |
||||||
|
return makeMovementFlags(dragFlags, swipeFlags); |
||||||
|
} |
||||||
|
} else if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
LinearLayoutManager linearLayoutManager = (LinearLayoutManager)layoutManager; |
||||||
|
if (linearLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL) { |
||||||
|
int dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; |
||||||
|
int swipeFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; |
||||||
|
return makeMovementFlags(dragFlags, swipeFlags); |
||||||
|
} else { |
||||||
|
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; |
||||||
|
int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; |
||||||
|
return makeMovementFlags(dragFlags, swipeFlags); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return makeMovementFlags(0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, |
||||||
|
int actionState, boolean isCurrentlyActive) { |
||||||
|
// 判断当前是否是swipe方式:侧滑。
|
||||||
|
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { |
||||||
|
//1.ItemView--ViewHolder; 2.侧滑条目的透明度程度关联谁?dX(delta增量,范围:当前条目-width~width)。
|
||||||
|
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); |
||||||
|
float alpha = 1; |
||||||
|
if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
int orientation = ((LinearLayoutManager)layoutManager).getOrientation(); |
||||||
|
if (orientation == LinearLayoutManager.HORIZONTAL) { |
||||||
|
alpha = 1 - Math.abs(dY) / viewHolder.itemView.getHeight(); |
||||||
|
} else if (orientation == LinearLayoutManager.VERTICAL) { |
||||||
|
alpha = 1 - Math.abs(dX) / viewHolder.itemView.getWidth(); |
||||||
|
} |
||||||
|
} |
||||||
|
viewHolder.itemView.setAlpha(alpha);//1~0
|
||||||
|
} |
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onMove(RecyclerView arg0, RecyclerView.ViewHolder srcHolder, RecyclerView.ViewHolder targetHolder) { |
||||||
|
if (onItemMoveListener != null) { |
||||||
|
// 回调刷新数据及界面。
|
||||||
|
return onItemMoveListener.onItemMove(srcHolder, targetHolder); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { |
||||||
|
// 回调刷新数据及界面。
|
||||||
|
if (onItemMoveListener != null) onItemMoveListener.onItemDismiss(viewHolder); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { |
||||||
|
super.onSelectedChanged(viewHolder, actionState); |
||||||
|
if (onItemStateChangedListener != null && actionState != OnItemStateChangedListener.ACTION_STATE_IDLE) { |
||||||
|
onItemStateChangedListener.onSelectedChanged(viewHolder, actionState); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { |
||||||
|
super.clearView(recyclerView, viewHolder); |
||||||
|
if (onItemStateChangedListener != null) { |
||||||
|
onItemStateChangedListener.onSelectedChanged(viewHolder, OnItemStateChangedListener.ACTION_STATE_IDLE); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.touch; |
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yolanda on 2016/4/19. |
||||||
|
*/ |
||||||
|
public interface OnItemMoveListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* When drag and drop the callback. |
||||||
|
* |
||||||
|
* @param srcHolder src. |
||||||
|
* @param targetHolder target. |
||||||
|
* |
||||||
|
* @return To deal with the returns true, false otherwise. |
||||||
|
*/ |
||||||
|
boolean onItemMove(RecyclerView.ViewHolder srcHolder, RecyclerView.ViewHolder targetHolder); |
||||||
|
|
||||||
|
/** |
||||||
|
* When items should be removed when the callback. |
||||||
|
* |
||||||
|
* @param srcHolder src. |
||||||
|
*/ |
||||||
|
void onItemDismiss(RecyclerView.ViewHolder srcHolder); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.touch; |
||||||
|
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/8/1. |
||||||
|
*/ |
||||||
|
public interface OnItemMovementListener { |
||||||
|
|
||||||
|
int INVALID = 0; |
||||||
|
|
||||||
|
int LEFT = ItemTouchHelper.LEFT; |
||||||
|
|
||||||
|
int UP = ItemTouchHelper.UP; |
||||||
|
|
||||||
|
int RIGHT = ItemTouchHelper.RIGHT; |
||||||
|
|
||||||
|
int DOWN = ItemTouchHelper.DOWN; |
||||||
|
|
||||||
|
/** |
||||||
|
* Can drag and drop the ViewHolder? |
||||||
|
* |
||||||
|
* @param recyclerView {@link RecyclerView}. |
||||||
|
* @param targetViewHolder target ViewHolder. |
||||||
|
* |
||||||
|
* @return use {@link #LEFT}, {@link #UP}, {@link #RIGHT}, {@link #DOWN}. |
||||||
|
*/ |
||||||
|
int onDragFlags(RecyclerView recyclerView, RecyclerView.ViewHolder targetViewHolder); |
||||||
|
|
||||||
|
/** |
||||||
|
* Can swipe and drop the ViewHolder? |
||||||
|
* |
||||||
|
* @param recyclerView {@link RecyclerView}. |
||||||
|
* @param targetViewHolder target ViewHolder. |
||||||
|
* |
||||||
|
* @return use {@link #LEFT}, {@link #UP}, {@link #RIGHT}, {@link #DOWN}. |
||||||
|
*/ |
||||||
|
int onSwipeFlags(RecyclerView recyclerView, RecyclerView.ViewHolder targetViewHolder); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2016 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.touch; |
||||||
|
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Yan Zhenjie on 2016/8/12. |
||||||
|
*/ |
||||||
|
public interface OnItemStateChangedListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* ItemTouchHelper is in idle state. At this state, either there is no related motion event by the user or latest |
||||||
|
* motion events have not yet triggered a swipe or drag. |
||||||
|
*/ |
||||||
|
int ACTION_STATE_IDLE = ItemTouchHelper.ACTION_STATE_IDLE; |
||||||
|
|
||||||
|
/** |
||||||
|
* A View is currently being swiped. |
||||||
|
*/ |
||||||
|
int ACTION_STATE_SWIPE = ItemTouchHelper.ACTION_STATE_SWIPE; |
||||||
|
|
||||||
|
/** |
||||||
|
* A View is currently being dragged. |
||||||
|
*/ |
||||||
|
int ACTION_STATE_DRAG = ItemTouchHelper.ACTION_STATE_DRAG; |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed. |
||||||
|
* |
||||||
|
* @param viewHolder The new ViewHolder that is being swiped or dragged. Might be null if it is cleared. |
||||||
|
* @param actionState One of {@link OnItemStateChangedListener#ACTION_STATE_IDLE}, {@link |
||||||
|
* OnItemStateChangedListener#ACTION_STATE_SWIPE} or {@link OnItemStateChangedListener#ACTION_STATE_DRAG}. |
||||||
|
*/ |
||||||
|
void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState); |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2019 Zhenjie Yan |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.widget; |
||||||
|
|
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
import androidx.annotation.ColorInt; |
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by Zhenjie Yan on 1/30/19. |
||||||
|
*/ |
||||||
|
public class BorderItemDecoration extends RecyclerView.ItemDecoration { |
||||||
|
|
||||||
|
private final int mWidth; |
||||||
|
private final int mHeight; |
||||||
|
private final Drawer mDrawer; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param color divider line color. |
||||||
|
*/ |
||||||
|
public BorderItemDecoration(@ColorInt int color) { |
||||||
|
this(color, 4, 4); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param color line color. |
||||||
|
* @param width line width. |
||||||
|
* @param height line height. |
||||||
|
*/ |
||||||
|
public BorderItemDecoration(@ColorInt int color, int width, int height) { |
||||||
|
this.mWidth = Math.round(width / 2F); |
||||||
|
this.mHeight = Math.round(height / 2F); |
||||||
|
this.mDrawer = new ColorDrawer(color, mWidth, mHeight); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, |
||||||
|
@NonNull RecyclerView.State state) { |
||||||
|
outRect.set(mWidth, mHeight, mWidth, mHeight); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { |
||||||
|
canvas.save(); |
||||||
|
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); |
||||||
|
assert layoutManager != null; |
||||||
|
int childCount = layoutManager.getChildCount(); |
||||||
|
for (int i = 0; i < childCount; i++) { |
||||||
|
final View view = layoutManager.getChildAt(i); |
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
canvas.restore(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2018 Yan Zhenjie. |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.widget; |
||||||
|
|
||||||
|
import android.graphics.Color; |
||||||
|
import android.graphics.drawable.ColorDrawable; |
||||||
|
|
||||||
|
import androidx.annotation.ColorInt; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2018/4/20. |
||||||
|
*/ |
||||||
|
public class ColorDrawer extends Drawer { |
||||||
|
|
||||||
|
public ColorDrawer(int color, int width, int height) { |
||||||
|
super(new ColorDrawable(opaqueColor(color)), width, height); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The target color is packaged in an opaque color. |
||||||
|
* |
||||||
|
* @param color color. |
||||||
|
* @return color. |
||||||
|
*/ |
||||||
|
@ColorInt |
||||||
|
public static int opaqueColor(@ColorInt int color) { |
||||||
|
int alpha = Color.alpha(color); |
||||||
|
if (alpha == 0) return color; |
||||||
|
int red = Color.red(color); |
||||||
|
int green = Color.green(color); |
||||||
|
int blue = Color.blue(color); |
||||||
|
return Color.argb(255, red, green, blue); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,380 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.widget; |
||||||
|
|
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.Rect; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
import androidx.annotation.ColorInt; |
||||||
|
import androidx.annotation.NonNull; |
||||||
|
import androidx.recyclerview.widget.GridLayoutManager; |
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager; |
||||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||||
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/8/14. |
||||||
|
*/ |
||||||
|
public class DefaultItemDecoration extends RecyclerView.ItemDecoration { |
||||||
|
|
||||||
|
private final int mWidth; |
||||||
|
private final int mHeight; |
||||||
|
private final Drawer mDrawer; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param color divider line color. |
||||||
|
*/ |
||||||
|
public DefaultItemDecoration(@ColorInt int color) { |
||||||
|
this(color, 4, 4); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param color line color. |
||||||
|
* @param width line width. |
||||||
|
* @param height line height. |
||||||
|
*/ |
||||||
|
public DefaultItemDecoration(@ColorInt int color, int width, int height) { |
||||||
|
this.mWidth = Math.round(width / 2F); |
||||||
|
this.mHeight = Math.round(height / 2F); |
||||||
|
this.mDrawer = new ColorDrawer(color, mWidth, mHeight); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, |
||||||
|
@NonNull RecyclerView.State state) { |
||||||
|
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); |
||||||
|
if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
int orientation = getOrientation(layoutManager); |
||||||
|
int position = parent.getChildLayoutPosition(view); |
||||||
|
int spanCount = getSpanCount(layoutManager); |
||||||
|
int childCount = layoutManager.getItemCount(); |
||||||
|
|
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
offsetVertical(outRect, position, spanCount, childCount); |
||||||
|
} else { |
||||||
|
offsetHorizontal(outRect, position, spanCount, childCount); |
||||||
|
} |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
outRect.set(mWidth, mHeight, mWidth, mHeight); // |-|-
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void offsetHorizontal(Rect outRect, int position, int spanCount, int childCount) { |
||||||
|
boolean firstRaw = isFirstRaw(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean lastRaw = isLastRaw(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean firstColumn = isFirstColumn(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean lastColumn = isLastColumn(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
|
||||||
|
if (spanCount == 1) { |
||||||
|
if (firstColumn && lastColumn) { // xxxx
|
||||||
|
outRect.set(0, 0, 0, 0); |
||||||
|
} else if (firstColumn) { // xx|x
|
||||||
|
outRect.set(0, 0, mWidth, 0); |
||||||
|
} else if (lastColumn) { // |xxx
|
||||||
|
outRect.set(mWidth, 0, 0, 0); |
||||||
|
} else { // |x|x
|
||||||
|
outRect.set(mWidth, 0, mWidth, 0); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (firstColumn && firstRaw) { // xx|-
|
||||||
|
outRect.set(0, 0, mWidth, mHeight); |
||||||
|
} else if (firstColumn && lastRaw) { // x-|x
|
||||||
|
outRect.set(0, mHeight, mWidth, 0); |
||||||
|
} else if (lastColumn && firstRaw) { // |xx-
|
||||||
|
outRect.set(mWidth, 0, 0, mHeight); |
||||||
|
} else if (lastColumn && lastRaw) { // |-xx
|
||||||
|
outRect.set(mWidth, mHeight, 0, 0); |
||||||
|
} else if (firstColumn) { // x-|-
|
||||||
|
outRect.set(0, mHeight, mWidth, mHeight); |
||||||
|
} else if (lastColumn) { // |-x-
|
||||||
|
outRect.set(mWidth, mHeight, 0, mHeight); |
||||||
|
} else if (firstRaw) { // |x|-
|
||||||
|
outRect.set(mWidth, 0, mWidth, mHeight); |
||||||
|
} else if (lastRaw) { // |-|x
|
||||||
|
outRect.set(mWidth, mHeight, mWidth, 0); |
||||||
|
} else { // |-|-
|
||||||
|
outRect.set(mWidth, mHeight, mWidth, mHeight); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void offsetVertical(Rect outRect, int position, int spanCount, int childCount) { |
||||||
|
boolean firstRaw = isFirstRaw(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean lastRaw = isLastRaw(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean firstColumn = isFirstColumn(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean lastColumn = isLastColumn(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
|
||||||
|
if (spanCount == 1) { |
||||||
|
if (firstRaw && lastRaw) { // xxxx
|
||||||
|
outRect.set(0, 0, 0, 0); |
||||||
|
} else if (firstRaw) { // xxx-
|
||||||
|
outRect.set(0, 0, 0, mHeight); |
||||||
|
} else if (lastRaw) { // x-xx
|
||||||
|
outRect.set(0, mHeight, 0, 0); |
||||||
|
} else { // x-x-
|
||||||
|
outRect.set(0, mHeight, 0, mHeight); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (firstRaw && firstColumn) { // xx|-
|
||||||
|
outRect.set(0, 0, mWidth, mHeight); |
||||||
|
} else if (firstRaw && lastColumn) { // |xx-
|
||||||
|
outRect.set(mWidth, 0, 0, mHeight); |
||||||
|
} else if (lastRaw && firstColumn) { // x-|x
|
||||||
|
outRect.set(0, mHeight, mWidth, 0); |
||||||
|
} else if (lastRaw && lastColumn) { // |-xx
|
||||||
|
outRect.set(mWidth, mHeight, 0, 0); |
||||||
|
} else if (firstRaw) { // |x|-
|
||||||
|
outRect.set(mWidth, 0, mWidth, mHeight); |
||||||
|
} else if (lastRaw) { // |-|x
|
||||||
|
outRect.set(mWidth, mHeight, mWidth, 0); |
||||||
|
} else if (firstColumn) { // x-|-
|
||||||
|
outRect.set(0, mHeight, mWidth, mHeight); |
||||||
|
} else if (lastColumn) { // |-x-
|
||||||
|
outRect.set(mWidth, mHeight, 0, mHeight); |
||||||
|
} else { // |-|-
|
||||||
|
outRect.set(mWidth, mHeight, mWidth, mHeight); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int getOrientation(RecyclerView.LayoutManager layoutManager) { |
||||||
|
if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
return ((LinearLayoutManager)layoutManager).getOrientation(); |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
return ((StaggeredGridLayoutManager)layoutManager).getOrientation(); |
||||||
|
} |
||||||
|
return RecyclerView.VERTICAL; |
||||||
|
} |
||||||
|
|
||||||
|
private int getSpanCount(RecyclerView.LayoutManager layoutManager) { |
||||||
|
if (layoutManager instanceof GridLayoutManager) { |
||||||
|
return ((GridLayoutManager)layoutManager).getSpanCount(); |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
return ((StaggeredGridLayoutManager)layoutManager).getSpanCount(); |
||||||
|
} |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isFirstRaw(int orientation, int position, int columnCount, int childCount) { |
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
return position < columnCount; |
||||||
|
} else { |
||||||
|
if (columnCount == 1) return true; |
||||||
|
return position % columnCount == 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isLastRaw(int orientation, int position, int columnCount, int childCount) { |
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
if (columnCount == 1) { |
||||||
|
return position + 1 == childCount; |
||||||
|
} else { |
||||||
|
int lastRawItemCount = childCount % columnCount; |
||||||
|
int rawCount = (childCount - lastRawItemCount) / columnCount + (lastRawItemCount > 0 ? 1 : 0); |
||||||
|
|
||||||
|
int rawPositionJudge = (position + 1) % columnCount; |
||||||
|
if (rawPositionJudge == 0) { |
||||||
|
int positionRaw = (position + 1) / columnCount; |
||||||
|
return rawCount == positionRaw; |
||||||
|
} else { |
||||||
|
int rawPosition = (position + 1 - rawPositionJudge) / columnCount + 1; |
||||||
|
return rawCount == rawPosition; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (columnCount == 1) return true; |
||||||
|
return (position + 1) % columnCount == 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isFirstColumn(int orientation, int position, int columnCount, int childCount) { |
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
if (columnCount == 1) return true; |
||||||
|
return position % columnCount == 0; |
||||||
|
} else { |
||||||
|
return position < columnCount; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isLastColumn(int orientation, int position, int columnCount, int childCount) { |
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
if (columnCount == 1) return true; |
||||||
|
return (position + 1) % columnCount == 0; |
||||||
|
} else { |
||||||
|
if (columnCount == 1) { |
||||||
|
return position + 1 == childCount; |
||||||
|
} else { |
||||||
|
int lastRawItemCount = childCount % columnCount; |
||||||
|
int rawCount = (childCount - lastRawItemCount) / columnCount + (lastRawItemCount > 0 ? 1 : 0); |
||||||
|
|
||||||
|
int rawPositionJudge = (position + 1) % columnCount; |
||||||
|
if (rawPositionJudge == 0) { |
||||||
|
int positionRaw = (position + 1) / columnCount; |
||||||
|
return rawCount == positionRaw; |
||||||
|
} else { |
||||||
|
int rawPosition = (position + 1 - rawPositionJudge) / columnCount + 1; |
||||||
|
return rawCount == rawPosition; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { |
||||||
|
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); |
||||||
|
assert layoutManager != null; |
||||||
|
int orientation = getOrientation(layoutManager); |
||||||
|
int spanCount = getSpanCount(layoutManager); |
||||||
|
int childCount = layoutManager.getChildCount(); |
||||||
|
|
||||||
|
if (layoutManager instanceof LinearLayoutManager) { |
||||||
|
canvas.save(); |
||||||
|
for (int i = 0; i < childCount; i++) { |
||||||
|
View view = layoutManager.getChildAt(i); |
||||||
|
assert view != null; |
||||||
|
int position = parent.getChildLayoutPosition(view); |
||||||
|
|
||||||
|
if (orientation == RecyclerView.VERTICAL) { |
||||||
|
drawVertical(canvas, view, position, spanCount, childCount); |
||||||
|
} else { |
||||||
|
drawHorizontal(canvas, view, position, spanCount, childCount); |
||||||
|
} |
||||||
|
} |
||||||
|
canvas.restore(); |
||||||
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) { |
||||||
|
canvas.save(); |
||||||
|
for (int i = 0; i < childCount; i++) { |
||||||
|
View view = layoutManager.getChildAt(i); |
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
canvas.restore(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void drawHorizontal(Canvas canvas, View view, int position, int spanCount, int childCount) { |
||||||
|
boolean firstRaw = isFirstRaw(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean lastRaw = isLastRaw(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean firstColumn = isFirstColumn(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
boolean lastColumn = isLastColumn(RecyclerView.HORIZONTAL, position, spanCount, childCount); |
||||||
|
|
||||||
|
if (spanCount == 1) { |
||||||
|
if (firstRaw && lastColumn) { // xxxx
|
||||||
|
// Nothing.
|
||||||
|
} else if (firstColumn) { // xx|x
|
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else if (lastColumn) { // |xxx
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
} else { // |x|x
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (firstColumn && firstRaw) { // xx|-
|
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (firstColumn && lastRaw) { // x-|x
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else if (lastColumn && firstRaw) { // |xx-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastColumn && lastRaw) { // |-xx
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
} else if (firstColumn) { // x-|-
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastColumn) { // |-x-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (firstRaw) { // |x|-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastRaw) { // |-|x
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else { // |-|-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void drawVertical(Canvas canvas, View view, int position, int spanCount, int childCount) { |
||||||
|
boolean firstRaw = isFirstRaw(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean lastRaw = isLastRaw(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean firstColumn = isFirstColumn(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
boolean lastColumn = isLastColumn(RecyclerView.VERTICAL, position, spanCount, childCount); |
||||||
|
|
||||||
|
if (spanCount == 1) { |
||||||
|
if (firstRaw && lastRaw) { // xxxx
|
||||||
|
// Nothing.
|
||||||
|
} else if (firstRaw) { // xxx-
|
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastRaw) { // x-xx
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
} else { // x-x-
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (firstRaw && firstColumn) { // xx|-
|
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (firstRaw && lastColumn) { // |xx-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastRaw && firstColumn) { // x-|x
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else if (lastRaw && lastColumn) { // |-xx
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
} else if (firstRaw) { // |x|-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastRaw) { // |-|x
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
} else if (firstColumn) { // x-|-
|
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else if (lastColumn) { // |-x-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} else { // |-|-
|
||||||
|
mDrawer.drawLeft(view, canvas); |
||||||
|
mDrawer.drawTop(view, canvas); |
||||||
|
mDrawer.drawRight(view, canvas); |
||||||
|
mDrawer.drawBottom(view, canvas); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.widget; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.text.TextUtils; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.util.DisplayMetrics; |
||||||
|
import android.view.Gravity; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
import android.widget.LinearLayout; |
||||||
|
import android.widget.ProgressBar; |
||||||
|
import android.widget.TextView; |
||||||
|
|
||||||
|
import androidx.annotation.Nullable; |
||||||
|
|
||||||
|
import com.project.survey.R; |
||||||
|
import com.project.survey.widget.swiperecyclerview.SwipeRecyclerView; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/7/21. |
||||||
|
*/ |
||||||
|
public class DefaultLoadMoreView extends LinearLayout implements SwipeRecyclerView.LoadMoreView, View.OnClickListener { |
||||||
|
|
||||||
|
private ProgressBar mProgressBar; |
||||||
|
private TextView mTvMessage; |
||||||
|
|
||||||
|
private SwipeRecyclerView.LoadMoreListener mLoadMoreListener; |
||||||
|
|
||||||
|
public DefaultLoadMoreView(Context context) { |
||||||
|
this(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public DefaultLoadMoreView(Context context, @Nullable AttributeSet attrs) { |
||||||
|
super(context, attrs); |
||||||
|
setLayoutParams(new ViewGroup.LayoutParams(-1, -2)); |
||||||
|
setGravity(Gravity.CENTER); |
||||||
|
setVisibility(GONE); |
||||||
|
|
||||||
|
DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); |
||||||
|
|
||||||
|
int minHeight = (int) (displayMetrics.density * 60 + 0.5); |
||||||
|
setMinimumHeight(minHeight); |
||||||
|
|
||||||
|
inflate(getContext(), R.layout.x_recycler_view_load_more, this); |
||||||
|
mProgressBar = findViewById(R.id.progress_bar); |
||||||
|
mTvMessage = findViewById(R.id.tv_load_more_message); |
||||||
|
setOnClickListener(this); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onLoading() { |
||||||
|
setVisibility(VISIBLE); |
||||||
|
mProgressBar.setVisibility(VISIBLE); |
||||||
|
mTvMessage.setVisibility(VISIBLE); |
||||||
|
mTvMessage.setText(R.string.x_recycler_load_more_message); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onLoadFinish(boolean dataEmpty, boolean hasMore) { |
||||||
|
if (!hasMore) { |
||||||
|
setVisibility(VISIBLE); |
||||||
|
|
||||||
|
if (dataEmpty) { |
||||||
|
mProgressBar.setVisibility(GONE); |
||||||
|
mTvMessage.setVisibility(VISIBLE); |
||||||
|
mTvMessage.setText(R.string.x_recycler_data_empty); |
||||||
|
} else { |
||||||
|
mProgressBar.setVisibility(GONE); |
||||||
|
mTvMessage.setVisibility(VISIBLE); |
||||||
|
mTvMessage.setText(R.string.x_recycler_more_not); |
||||||
|
} |
||||||
|
} else { |
||||||
|
setVisibility(INVISIBLE); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onWaitToLoadMore(SwipeRecyclerView.LoadMoreListener loadMoreListener) { |
||||||
|
this.mLoadMoreListener = loadMoreListener; |
||||||
|
|
||||||
|
setVisibility(VISIBLE); |
||||||
|
mProgressBar.setVisibility(GONE); |
||||||
|
mTvMessage.setVisibility(VISIBLE); |
||||||
|
mTvMessage.setText(R.string.x_recycler_click_load_more); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onLoadError(int errorCode, String errorMessage) { |
||||||
|
setVisibility(VISIBLE); |
||||||
|
mProgressBar.setVisibility(GONE); |
||||||
|
mTvMessage.setVisibility(VISIBLE); |
||||||
|
mTvMessage.setText( |
||||||
|
TextUtils.isEmpty(errorMessage) ? getContext().getString(R.string.x_recycler_load_error) : errorMessage); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onClick(View v) { |
||||||
|
if (mLoadMoreListener != null) mLoadMoreListener.onLoadMore(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2018 Yan Zhenjie. |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.widget; |
||||||
|
|
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.drawable.Drawable; |
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2018/4/20. |
||||||
|
*/ |
||||||
|
public class Drawer { |
||||||
|
|
||||||
|
private final Drawable mDivider; |
||||||
|
private final int mWidth; |
||||||
|
private final int mHeight; |
||||||
|
|
||||||
|
public Drawer(Drawable divider, int width, int height) { |
||||||
|
this.mDivider = divider; |
||||||
|
this.mWidth = width; |
||||||
|
this.mHeight = height; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Draw the divider on the left side of the Item. |
||||||
|
*/ |
||||||
|
public void drawLeft(View view, Canvas c) { |
||||||
|
int left = view.getLeft() - mWidth; |
||||||
|
int top = view.getTop() - mHeight; |
||||||
|
int right = left + mWidth; |
||||||
|
int bottom = view.getBottom() + mHeight; |
||||||
|
mDivider.setBounds(left, top, right, bottom); |
||||||
|
mDivider.draw(c); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Draw the divider on the top side of the Item. |
||||||
|
*/ |
||||||
|
public void drawTop(View view, Canvas c) { |
||||||
|
int left = view.getLeft() - mWidth; |
||||||
|
int top = view.getTop() - mHeight; |
||||||
|
int right = view.getRight() + mWidth; |
||||||
|
int bottom = top + mHeight; |
||||||
|
mDivider.setBounds(left, top, right, bottom); |
||||||
|
mDivider.draw(c); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Draw the divider on the top side of the Item. |
||||||
|
*/ |
||||||
|
public void drawRight(View view, Canvas c) { |
||||||
|
int left = view.getRight(); |
||||||
|
int top = view.getTop() - mHeight; |
||||||
|
int right = left + mWidth; |
||||||
|
int bottom = view.getBottom() + mHeight; |
||||||
|
mDivider.setBounds(left, top, right, bottom); |
||||||
|
mDivider.draw(c); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Draw the divider on the top side of the Item. |
||||||
|
*/ |
||||||
|
public void drawBottom(View view, Canvas c) { |
||||||
|
int left = view.getLeft() - mWidth; |
||||||
|
int top = view.getBottom(); |
||||||
|
int right = view.getRight() + mWidth; |
||||||
|
int bottom = top + mHeight; |
||||||
|
mDivider.setBounds(left, top, right, bottom); |
||||||
|
mDivider.draw(c); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,406 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2017 Yan Zhenjie |
||||||
|
* |
||||||
|
* 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.project.survey.widget.swiperecyclerview.widget; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.graphics.Canvas; |
||||||
|
import android.graphics.drawable.Drawable; |
||||||
|
import android.util.AttributeSet; |
||||||
|
import android.view.MotionEvent; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
|
||||||
|
import androidx.core.widget.NestedScrollView; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Created by YanZhenjie on 2017/7/20. |
||||||
|
*/ |
||||||
|
public class StickyNestedScrollView extends NestedScrollView { |
||||||
|
|
||||||
|
public interface OnViewStickyListener { |
||||||
|
|
||||||
|
void onSticky(View view); |
||||||
|
|
||||||
|
void onUnSticky(View view); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Tag for views that should stick and have constant drawing. e.g. TextViews, ImageViews etc |
||||||
|
*/ |
||||||
|
public static final String STICKY_TAG = "sticky"; |
||||||
|
/** |
||||||
|
* Flag for views that should stick and have non-constant drawing. e.g. Buttons, ProgressBars etc |
||||||
|
*/ |
||||||
|
public static final String FLAG_NONCONSTANT = "-nonconstant"; |
||||||
|
/** |
||||||
|
* Flag for views that have aren't fully opaque |
||||||
|
*/ |
||||||
|
public static final String FLAG_HASTRANSPARENCY = "-hastransparency"; |
||||||
|
/** |
||||||
|
* Default height of the shadow peeking out below the stuck view. |
||||||
|
*/ |
||||||
|
private static final int DEFAULT_SHADOW_HEIGHT = 10; // dp;
|
||||||
|
private ArrayList<View> stickyViews; |
||||||
|
private View currentlyStickingView; |
||||||
|
private float stickyViewTopOffset; |
||||||
|
private final Runnable invalidateRunnable = new Runnable() { |
||||||
|
@Override |
||||||
|
public void run() { |
||||||
|
if (currentlyStickingView != null) { |
||||||
|
int l = getLeftForViewRelativeOnlyChild(currentlyStickingView); |
||||||
|
int t = getBottomForViewRelativeOnlyChild(currentlyStickingView); |
||||||
|
int r = getRightForViewRelativeOnlyChild(currentlyStickingView); |
||||||
|
int b = (int)(getScrollY() + (currentlyStickingView.getHeight() + stickyViewTopOffset)); |
||||||
|
invalidate(l, t, r, b); |
||||||
|
} |
||||||
|
postDelayed(this, 16); |
||||||
|
} |
||||||
|
}; |
||||||
|
private int stickyViewLeftOffset; |
||||||
|
private boolean redirectTouchesToStickyView; |
||||||
|
private boolean clippingToPadding; |
||||||
|
private boolean clipToPaddingHasBeenSet; |
||||||
|
private int mShadowHeight = DEFAULT_SHADOW_HEIGHT; |
||||||
|
private Drawable mShadowDrawable; |
||||||
|
private boolean hasNotDoneActionDown = true; |
||||||
|
|
||||||
|
private List<OnViewStickyListener> mOnViewStickyListeners; |
||||||
|
|
||||||
|
public StickyNestedScrollView(Context context) { |
||||||
|
this(context, null); |
||||||
|
} |
||||||
|
|
||||||
|
public StickyNestedScrollView(Context context, AttributeSet attrs) { |
||||||
|
this(context, attrs, android.R.attr.scrollViewStyle); |
||||||
|
} |
||||||
|
|
||||||
|
public StickyNestedScrollView(Context context, AttributeSet attrs, int defStyle) { |
||||||
|
super(context, attrs, defStyle); |
||||||
|
setup(); |
||||||
|
} |
||||||
|
|
||||||
|
public void addOnViewStickyListener(OnViewStickyListener stickyListener) { |
||||||
|
if (mOnViewStickyListeners == null) mOnViewStickyListeners = new ArrayList<>(); |
||||||
|
mOnViewStickyListeners.add(stickyListener); |
||||||
|
} |
||||||
|
|
||||||
|
public void removeOnViewStickyListener(OnViewStickyListener stickyListener) { |
||||||
|
if (mOnViewStickyListeners != null) mOnViewStickyListeners.remove(stickyListener); |
||||||
|
} |
||||||
|
|
||||||
|
public void clearOnViewStickyListener() { |
||||||
|
if (mOnViewStickyListeners != null) mOnViewStickyListeners.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
public void setShadowHeight(int height) { |
||||||
|
mShadowHeight = height; |
||||||
|
} |
||||||
|
|
||||||
|
public void setShadowDrawable(Drawable shadowDrawable) { |
||||||
|
mShadowDrawable = shadowDrawable; |
||||||
|
} |
||||||
|
|
||||||
|
public void setup() { |
||||||
|
stickyViews = new ArrayList<>(); |
||||||
|
} |
||||||
|
|
||||||
|
private int getLeftForViewRelativeOnlyChild(View v) { |
||||||
|
int left = v.getLeft(); |
||||||
|
while (v.getParent() != null && v.getParent() != getChildAt(0)) { |
||||||
|
v = (View)v.getParent(); |
||||||
|
left += v.getLeft(); |
||||||
|
} |
||||||
|
return left; |
||||||
|
} |
||||||
|
|
||||||
|
private int getTopForViewRelativeOnlyChild(View v) { |
||||||
|
int top = v.getTop(); |
||||||
|
while (v.getParent() != null && v.getParent() != getChildAt(0)) { |
||||||
|
v = (View)v.getParent(); |
||||||
|
top += v.getTop(); |
||||||
|
} |
||||||
|
return top; |
||||||
|
} |
||||||
|
|
||||||
|
private int getRightForViewRelativeOnlyChild(View v) { |
||||||
|
int right = v.getRight(); |
||||||
|
while (v.getParent() != null && v.getParent() != getChildAt(0)) { |
||||||
|
v = (View)v.getParent(); |
||||||
|
right += v.getRight(); |
||||||
|
} |
||||||
|
return right; |
||||||
|
} |
||||||
|
|
||||||
|
private int getBottomForViewRelativeOnlyChild(View v) { |
||||||
|
int bottom = v.getBottom(); |
||||||
|
while (v.getParent() != null && v.getParent() != getChildAt(0)) { |
||||||
|
v = (View)v.getParent(); |
||||||
|
bottom += v.getBottom(); |
||||||
|
} |
||||||
|
return bottom; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onLayout(boolean changed, int l, int t, int r, int b) { |
||||||
|
super.onLayout(changed, l, t, r, b); |
||||||
|
if (!clipToPaddingHasBeenSet) { |
||||||
|
clippingToPadding = true; |
||||||
|
} |
||||||
|
notifyHierarchyChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setClipToPadding(boolean clipToPadding) { |
||||||
|
super.setClipToPadding(clipToPadding); |
||||||
|
clippingToPadding = clipToPadding; |
||||||
|
clipToPaddingHasBeenSet = true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void addView(View child) { |
||||||
|
super.addView(child); |
||||||
|
findStickyViews(child); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void addView(View child, int index) { |
||||||
|
super.addView(child, index); |
||||||
|
findStickyViews(child); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void addView(View child, int index, ViewGroup.LayoutParams params) { |
||||||
|
super.addView(child, index, params); |
||||||
|
findStickyViews(child); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void addView(View child, int width, int height) { |
||||||
|
super.addView(child, width, height); |
||||||
|
findStickyViews(child); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void addView(View child, ViewGroup.LayoutParams params) { |
||||||
|
super.addView(child, params); |
||||||
|
findStickyViews(child); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void dispatchDraw(Canvas canvas) { |
||||||
|
super.dispatchDraw(canvas); |
||||||
|
if (currentlyStickingView != null) { |
||||||
|
canvas.save(); |
||||||
|
canvas.translate(getPaddingLeft() + stickyViewLeftOffset, |
||||||
|
getScrollY() + stickyViewTopOffset + (clippingToPadding ? getPaddingTop() : 0)); |
||||||
|
canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth() - stickyViewLeftOffset, |
||||||
|
currentlyStickingView.getHeight() + mShadowHeight + 1); |
||||||
|
if (mShadowDrawable != null) { |
||||||
|
int left = 0; |
||||||
|
int top = currentlyStickingView.getHeight(); |
||||||
|
int right = currentlyStickingView.getWidth(); |
||||||
|
int bottom = currentlyStickingView.getHeight() + mShadowHeight; |
||||||
|
mShadowDrawable.setBounds(left, top, right, bottom); |
||||||
|
mShadowDrawable.draw(canvas); |
||||||
|
} |
||||||
|
canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth(), |
||||||
|
currentlyStickingView.getHeight()); |
||||||
|
if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARENCY)) { |
||||||
|
showView(currentlyStickingView); |
||||||
|
currentlyStickingView.draw(canvas); |
||||||
|
hideView(currentlyStickingView); |
||||||
|
} else { |
||||||
|
currentlyStickingView.draw(canvas); |
||||||
|
} |
||||||
|
canvas.restore(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean dispatchTouchEvent(MotionEvent ev) { |
||||||
|
if (ev.getAction() == MotionEvent.ACTION_DOWN) { |
||||||
|
redirectTouchesToStickyView = true; |
||||||
|
} |
||||||
|
if (redirectTouchesToStickyView) { |
||||||
|
redirectTouchesToStickyView = currentlyStickingView != null; |
||||||
|
if (redirectTouchesToStickyView) { |
||||||
|
redirectTouchesToStickyView = ev.getY() <= (currentlyStickingView.getHeight() + stickyViewTopOffset) && |
||||||
|
ev.getX() >= getLeftForViewRelativeOnlyChild(currentlyStickingView) && |
||||||
|
ev.getX() <= getRightForViewRelativeOnlyChild(currentlyStickingView); |
||||||
|
} |
||||||
|
} else if (currentlyStickingView == null) { |
||||||
|
redirectTouchesToStickyView = false; |
||||||
|
} |
||||||
|
if (redirectTouchesToStickyView) { |
||||||
|
ev.offsetLocation(0, |
||||||
|
-1 * ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView))); |
||||||
|
} |
||||||
|
return super.dispatchTouchEvent(ev); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean onTouchEvent(MotionEvent ev) { |
||||||
|
if (redirectTouchesToStickyView) { |
||||||
|
ev.offsetLocation(0, |
||||||
|
((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView))); |
||||||
|
} |
||||||
|
if (ev.getAction() == MotionEvent.ACTION_DOWN) { |
||||||
|
hasNotDoneActionDown = false; |
||||||
|
} |
||||||
|
if (hasNotDoneActionDown) { |
||||||
|
MotionEvent down = MotionEvent.obtain(ev); |
||||||
|
down.setAction(MotionEvent.ACTION_DOWN); |
||||||
|
super.onTouchEvent(down); |
||||||
|
hasNotDoneActionDown = false; |
||||||
|
} |
||||||
|
if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { |
||||||
|
hasNotDoneActionDown = true; |
||||||
|
} |
||||||
|
return super.onTouchEvent(ev); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onScrollChanged(int l, int t, int oldl, int oldt) { |
||||||
|
super.onScrollChanged(l, t, oldl, oldt); |
||||||
|
doTheStickyThing(); |
||||||
|
} |
||||||
|
|
||||||
|
private void doTheStickyThing() { |
||||||
|
View viewThatShouldStick = null; |
||||||
|
View approachingView = null; |
||||||
|
for (View v : stickyViews) { |
||||||
|
int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()); |
||||||
|
if (viewTop <= 0) { |
||||||
|
if (viewThatShouldStick == null || viewTop > |
||||||
|
(getTopForViewRelativeOnlyChild(viewThatShouldStick) - getScrollY() + |
||||||
|
(clippingToPadding ? 0 : getPaddingTop()))) { |
||||||
|
viewThatShouldStick = v; |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (approachingView == null || viewTop < |
||||||
|
(getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + |
||||||
|
(clippingToPadding ? 0 : getPaddingTop()))) { |
||||||
|
approachingView = v; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (viewThatShouldStick != null) { |
||||||
|
stickyViewTopOffset = approachingView == null |
||||||
|
? 0 |
||||||
|
: Math.min(0, getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + |
||||||
|
(clippingToPadding ? 0 : getPaddingTop()) - viewThatShouldStick.getHeight()); |
||||||
|
if (viewThatShouldStick != currentlyStickingView) { |
||||||
|
if (currentlyStickingView != null) { |
||||||
|
if (mOnViewStickyListeners != null) { |
||||||
|
for (OnViewStickyListener onViewStickyListener : mOnViewStickyListeners) |
||||||
|
onViewStickyListener.onUnSticky(currentlyStickingView); |
||||||
|
} |
||||||
|
stopStickingCurrentlyStickingView(); |
||||||
|
} |
||||||
|
// only compute the left offset when we start sticking.
|
||||||
|
stickyViewLeftOffset = getLeftForViewRelativeOnlyChild(viewThatShouldStick); |
||||||
|
startStickingView(viewThatShouldStick); |
||||||
|
if (mOnViewStickyListeners != null) { |
||||||
|
for (OnViewStickyListener onViewStickyListener : mOnViewStickyListeners) |
||||||
|
onViewStickyListener.onSticky(currentlyStickingView); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (currentlyStickingView != null) { |
||||||
|
if (mOnViewStickyListeners != null) { |
||||||
|
for (OnViewStickyListener onViewStickyListener : mOnViewStickyListeners) |
||||||
|
onViewStickyListener.onUnSticky(currentlyStickingView); |
||||||
|
} |
||||||
|
stopStickingCurrentlyStickingView(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void startStickingView(View viewThatShouldStick) { |
||||||
|
currentlyStickingView = viewThatShouldStick; |
||||||
|
if (currentlyStickingView != null) { |
||||||
|
if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARENCY)) { |
||||||
|
hideView(currentlyStickingView); |
||||||
|
} |
||||||
|
if (getStringTagForView(currentlyStickingView).contains(FLAG_NONCONSTANT)) { |
||||||
|
post(invalidateRunnable); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void stopStickingCurrentlyStickingView() { |
||||||
|
if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARENCY)) { |
||||||
|
showView(currentlyStickingView); |
||||||
|
} |
||||||
|
currentlyStickingView = null; |
||||||
|
removeCallbacks(invalidateRunnable); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onDetachedFromWindow() { |
||||||
|
removeCallbacks(invalidateRunnable); |
||||||
|
super.onDetachedFromWindow(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Notify that the sticky attribute has been added or removed from one or more views in the View hierarchy |
||||||
|
*/ |
||||||
|
public void notifyStickyAttributeChanged() { |
||||||
|
notifyHierarchyChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
private void notifyHierarchyChanged() { |
||||||
|
if (currentlyStickingView != null) { |
||||||
|
stopStickingCurrentlyStickingView(); |
||||||
|
} |
||||||
|
stickyViews.clear(); |
||||||
|
findStickyViews(getChildAt(0)); |
||||||
|
doTheStickyThing(); |
||||||
|
invalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
private void findStickyViews(View v) { |
||||||
|
if (!detainStickyView(v) && (v instanceof ViewGroup)) { |
||||||
|
ViewGroup vg = (ViewGroup)v; |
||||||
|
for (int i = 0; i < vg.getChildCount(); i++) |
||||||
|
findStickyViews(vg.getChildAt(i)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean detainStickyView(View view) { |
||||||
|
String tag = getStringTagForView(view); |
||||||
|
if (tag.contains(STICKY_TAG)) { |
||||||
|
stickyViews.add(view); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private String getStringTagForView(View v) { |
||||||
|
Object tagObject = v.getTag(); |
||||||
|
return String.valueOf(tagObject); |
||||||
|
} |
||||||
|
|
||||||
|
private void hideView(View v) { |
||||||
|
v.setAlpha(0); |
||||||
|
} |
||||||
|
|
||||||
|
private void showView(View v) { |
||||||
|
v.setAlpha(1); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:shape="rectangle"> |
||||||
|
<corners android:radius="99dp" /> |
||||||
|
<solid android:color="#f2f4f5" /> |
||||||
|
</shape> |
@ -0,0 +1,8 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:shape="rectangle"> |
||||||
|
<gradient |
||||||
|
android:angle="270" |
||||||
|
android:endColor="#ffffff" |
||||||
|
android:startColor="#1A000000" /> |
||||||
|
</shape> |
@ -0,0 +1,10 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="16.5dp" |
||||||
|
android:height="16.5dp" |
||||||
|
android:viewportWidth="16.5" |
||||||
|
android:viewportHeight="16.5"> |
||||||
|
<path |
||||||
|
android:pathData="M0,0L7.333,0L7.333,9.167L0,9.167L0,0ZM9.167,0L16.5,0L16.5,5.5L9.167,5.5L9.167,0ZM5.5,7.333L5.5,1.833L1.833,1.833L1.833,7.333L5.5,7.333ZM14.667,3.667L14.667,1.833L11,1.833L11,3.667L14.667,3.667ZM9.167,7.333L16.5,7.333L16.5,16.5L9.167,16.5L9.167,7.333ZM14.667,14.667L14.667,9.167L11,9.167L11,14.667L14.667,14.667ZM0,11L7.333,11L7.333,16.5L0,16.5L0,11ZM5.5,14.667L5.5,12.833L1.833,12.833L1.833,14.667L5.5,14.667Z" |
||||||
|
android:fillColor="#5B5A5E" |
||||||
|
android:fillType="evenOdd"/> |
||||||
|
</vector> |
@ -0,0 +1,13 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="30dp" |
||||||
|
android:height="30dp" |
||||||
|
android:viewportWidth="30" |
||||||
|
android:viewportHeight="30"> |
||||||
|
<path |
||||||
|
android:pathData="M0,15a15,15 0,1 0,30 0a15,15 0,1 0,-30 0z" |
||||||
|
android:fillColor="#E9F1FC"/> |
||||||
|
<path |
||||||
|
android:pathData="M10.5,8L19.5,8C20.325,8 21,8.63 21,9.4L21,20.6C21,21.37 20.325,22 19.5,22L10.5,22C9.675,22 9,21.37 9,20.6L9,9.4C9,8.63 9.675,8 10.5,8ZM14.25,9.4L10.5,9.4L10.5,15L12.375,13.95L14.25,15L14.25,9.4Z" |
||||||
|
android:fillColor="#396BD0" |
||||||
|
android:fillType="evenOdd"/> |
||||||
|
</vector> |
@ -0,0 +1,10 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="18.333dp" |
||||||
|
android:height="18.333dp" |
||||||
|
android:viewportWidth="18.333" |
||||||
|
android:viewportHeight="18.333"> |
||||||
|
<path |
||||||
|
android:pathData="M9.167,0C4.125,0 0,4.125 0,9.167C0,14.208 4.125,18.333 9.167,18.333C14.208,18.333 18.333,14.208 18.333,9.167C18.333,4.125 14.208,0 9.167,0ZM1.833,9.167C1.833,13.209 5.124,16.5 9.167,16.5C13.209,16.5 16.5,13.209 16.5,9.167C16.5,5.124 13.209,1.833 9.167,1.833C5.124,1.833 1.833,5.124 1.833,9.167ZM9.625,4.583L8.25,4.583L8.25,10.083L13.017,13.017L13.75,11.825L9.625,9.35L9.625,4.583Z" |
||||||
|
android:fillColor="#396BD0" |
||||||
|
android:fillType="evenOdd"/> |
||||||
|
</vector> |
@ -0,0 +1,10 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="13.117dp" |
||||||
|
android:height="13.117dp" |
||||||
|
android:viewportWidth="13.117" |
||||||
|
android:viewportHeight="13.117"> |
||||||
|
<path |
||||||
|
android:pathData="M8.783,8.25L9.375,8.25L13.118,12L12,13.118L8.25,9.375L8.25,8.783L8.047,8.573C7.193,9.307 6.082,9.75 4.875,9.75C2.182,9.75 0,7.568 0,4.875C0,2.182 2.182,0 4.875,0C7.568,0 9.75,2.182 9.75,4.875C9.75,6.082 9.307,7.193 8.573,8.047L8.783,8.25ZM1.5,4.875C1.5,6.742 3.007,8.25 4.875,8.25C6.742,8.25 8.25,6.742 8.25,4.875C8.25,3.007 6.742,1.5 4.875,1.5C3.007,1.5 1.5,3.007 1.5,4.875Z" |
||||||
|
android:fillColor="#727778" |
||||||
|
android:fillType="evenOdd"/> |
||||||
|
</vector> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent"> |
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout> |
@ -0,0 +1,36 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:tl="http://schemas.android.com/apk/res-auto" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<include |
||||||
|
android:id="@+id/ilToolBar" |
||||||
|
layout="@layout/toolbar" /> |
||||||
|
|
||||||
|
<include layout="@layout/item_search" /> |
||||||
|
|
||||||
|
<androidx.fragment.app.FragmentContainerView |
||||||
|
android:id="@+id/container" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="0dp" |
||||||
|
android:layout_weight="1" /> |
||||||
|
|
||||||
|
<com.flyco.tablayout.CommonTabLayout |
||||||
|
android:id="@+id/tabLayout" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="54dp" |
||||||
|
android:background="#ffffff" |
||||||
|
tl:tl_iconHeight="23dp" |
||||||
|
tl:tl_iconWidth="23dp" |
||||||
|
tl:tl_indicator_color="#3498db" |
||||||
|
tl:tl_indicator_height="0dp" |
||||||
|
tl:tl_textSelectColor="#3498db" |
||||||
|
tl:tl_textUnselectColor="#666666" |
||||||
|
tl:tl_textsize="12sp" |
||||||
|
tl:tl_underline_color="#cfcfcf" |
||||||
|
tl:tl_underline_gravity="TOP" |
||||||
|
tl:tl_underline_height="1dp" /> |
||||||
|
|
||||||
|
</LinearLayout> |
@ -0,0 +1,10 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||||
|
android:id="@+id/recyclerView" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:paddingHorizontal="@dimen/sw_16dp" |
||||||
|
android:paddingVertical="@dimen/sw_6dp" |
||||||
|
android:scrollbars="vertical" |
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> |
@ -0,0 +1,57 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:orientation="horizontal" |
||||||
|
android:paddingVertical="@dimen/sw_18dp"> |
||||||
|
|
||||||
|
<ImageView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:src="@drawable/ic_project_list" /> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginStart="@dimen/sw_14dp" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tvProjectName" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:textColor="@color/text_color_1" |
||||||
|
android:textSize="@dimen/sw_15sp" |
||||||
|
android:textStyle="bold" |
||||||
|
android:text="xx工程" /> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginTop="@dimen/sw_3dp" |
||||||
|
android:orientation="horizontal"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tvProjectNum" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:textColor="@color/text_color_2" |
||||||
|
android:textSize="@dimen/sw_11sp" |
||||||
|
android:text="XMBH2021-00001" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tvProjectArea" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:textColor="@color/text_color_2" |
||||||
|
android:textSize="@dimen/sw_11sp" |
||||||
|
android:text="上海市长宁区" /> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
</LinearLayout> |
@ -0,0 +1,42 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="@dimen/sw_30dp" |
||||||
|
android:layout_marginHorizontal="@dimen/sw_16dp" |
||||||
|
android:layout_marginVertical="@dimen/sw_7dp" |
||||||
|
android:background="@drawable/bg_search" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:orientation="horizontal" |
||||||
|
android:paddingHorizontal="@dimen/sw_18dp"> |
||||||
|
|
||||||
|
<ImageView |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:src="@drawable/ic_search" /> |
||||||
|
|
||||||
|
<EditText |
||||||
|
android:id="@+id/etSearch" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:background="@null" |
||||||
|
android:hint="请输入" |
||||||
|
android:paddingStart="6dp" |
||||||
|
android:textColor="@color/text_color_1" |
||||||
|
android:textColorHint="@color/text_color_2" |
||||||
|
android:textSize="@dimen/sw_11sp" /> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
|
||||||
|
<View |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="@dimen/sw_2dp" |
||||||
|
android:background="@drawable/bg_search_shadow_2" /> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
@ -0,0 +1,39 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- |
||||||
|
Copyright 2017 Yan Zhenjie |
||||||
|
|
||||||
|
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. |
||||||
|
--> |
||||||
|
<com.project.survey.widget.swiperecyclerview.SwipeMenuLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
app:contentViewId="@+id/swipe_content" |
||||||
|
app:leftViewId="@+id/swipe_left" |
||||||
|
app:rightViewId="@+id/swipe_right"> |
||||||
|
|
||||||
|
<com.project.survey.widget.swiperecyclerview.SwipeMenuView |
||||||
|
android:id="@+id/swipe_left" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" /> |
||||||
|
|
||||||
|
<FrameLayout |
||||||
|
android:id="@+id/swipe_content" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" /> |
||||||
|
|
||||||
|
<com.project.survey.widget.swiperecyclerview.SwipeMenuView |
||||||
|
android:id="@+id/swipe_right" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="match_parent" /> |
||||||
|
|
||||||
|
</com.project.survey.widget.swiperecyclerview.SwipeMenuLayout> |
@ -0,0 +1,37 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- |
||||||
|
Copyright 2017 Yan Zhenjie |
||||||
|
|
||||||
|
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. |
||||||
|
--> |
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:tools="http://schemas.android.com/tools"> |
||||||
|
|
||||||
|
<ProgressBar |
||||||
|
android:id="@+id/progress_bar" |
||||||
|
style="@android:style/Widget.Holo.ProgressBar" |
||||||
|
android:layout_width="32dp" |
||||||
|
android:layout_height="32dp" |
||||||
|
android:visibility="gone" |
||||||
|
tools:visibility="invisible" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_load_more_message" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:textColor="@color/text_color_2" |
||||||
|
android:visibility="gone" |
||||||
|
tools:text="Loading..." |
||||||
|
tools:visibility="invisible" /> |
||||||
|
|
||||||
|
</merge> |
@ -1,78 +1,17 @@ |
|||||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||||
<resources> |
<resources> |
||||||
<!--以下全部为ChatUI的属性--> |
<declare-styleable name="Verificationcode"> |
||||||
<declare-styleable name="BubbleView"> |
<attr name="code_text_color" format="color" />//验证码字体颜色 |
||||||
<attr name="arrowWidth" format="dimension" /> |
<attr name="code_text_size" format="dimension" />//验证码字体大小 |
||||||
<attr name="angle" format="dimension" /> |
<attr name="code_number" format="integer" />//验证码数量 4位 6位 |
||||||
<attr name="arrowHeight" format="dimension" /> |
<attr name="line_color_default" format="color" />//验证码下面线的默认颜色 |
||||||
<attr name="arrowPosition" format="dimension" /> |
<attr name="line_color_focus" format="color" />//验证码下面线选中后的颜色 |
||||||
<attr name="bubbleColor" format="color" /> |
|
||||||
<attr name="arrowLocation" format="enum"> |
|
||||||
<enum name="left" value="0x00" /> |
|
||||||
<enum name="right" value="0x01" /> |
|
||||||
<enum name="top" value="0x02" /> |
|
||||||
<enum name="bottom" value="0x03" /> |
|
||||||
</attr> |
|
||||||
</declare-styleable> |
|
||||||
|
|
||||||
<declare-styleable name="RotateLayout"> |
|
||||||
<!-- Child view of this layout will be rotated by this angle. --> |
|
||||||
<attr name="rotate_angle" format="integer" /> |
|
||||||
</declare-styleable> |
|
||||||
|
|
||||||
<declare-styleable name="TextItem"> |
|
||||||
<attr name="text" format="string" /> |
|
||||||
<attr name="text_size" format="dimension" /> |
|
||||||
<attr name="text_color" format="color" /> |
|
||||||
<attr name="dividerVisible" format="enum"> |
|
||||||
<enum name="visible" value="0" /> |
|
||||||
<enum name="invisible" value="1" /> |
|
||||||
</attr> |
|
||||||
<attr name="text_gravity" format="enum"> |
|
||||||
<enum name="start" value="0" /> |
|
||||||
<enum name="center" value="1" /> |
|
||||||
<enum name="end" value="2" /> |
|
||||||
</attr> |
|
||||||
</declare-styleable> |
|
||||||
|
|
||||||
<declare-styleable name="TextItemWithDescribe"> |
|
||||||
<attr name="describeValue" format="string" /> |
|
||||||
</declare-styleable> |
|
||||||
|
|
||||||
<declare-styleable name="customAttrs"> |
|
||||||
<attr name="efp__selected_item_background" format="reference" /> |
|
||||||
<attr name="efp__ic_action_cancel" format="reference" /> |
|
||||||
<attr name="efp__ic_action_deselect" format="reference" /> |
|
||||||
<attr name="efp__ic_action_grid" format="reference" /> |
|
||||||
<attr name="efp__ic_action_invert_selection" format="reference" /> |
|
||||||
<attr name="efp__ic_action_list" format="reference" /> |
|
||||||
<attr name="efp__ic_action_new_folder" format="reference" /> |
|
||||||
<attr name="efp__ic_action_ok" format="reference" /> |
|
||||||
<attr name="efp__ic_action_select_all" format="reference" /> |
|
||||||
<attr name="efp__ic_action_sort" format="reference" /> |
|
||||||
<attr name="efp__ic_action_storage" format="reference" /> |
|
||||||
</declare-styleable> |
|
||||||
|
|
||||||
<declare-styleable name="SwitchWithText"> |
|
||||||
<attr name="name" format="string" /> |
|
||||||
<attr name="onText" format="string" /> |
|
||||||
<attr name="offText" format="string" /> |
|
||||||
<attr name="onChecked" format="boolean" /> |
|
||||||
</declare-styleable> |
|
||||||
|
|
||||||
<declare-styleable name="EditSpinner"> |
|
||||||
<attr name="hint" format="string"/> |
|
||||||
<attr name="rightImage" format="reference"/> |
|
||||||
<attr name="Background" format="reference"/> |
|
||||||
<attr name="maxLine" format="integer"/> |
|
||||||
</declare-styleable> |
</declare-styleable> |
||||||
|
|
||||||
<declare-styleable name="Verificationcode"> |
<declare-styleable name="SwipeMenuLayout"> |
||||||
<attr format="color" name="code_text_color"/>//验证码字体颜色 |
<attr name="leftViewId" format="reference|integer" /> |
||||||
<attr format="dimension" name="code_text_size"/>//验证码字体大小 |
<attr name="rightViewId" format="reference|integer" /> |
||||||
<attr format="integer" name="code_number"/>//验证码数量 4位 6位 |
<attr name="contentViewId" format="reference|integer" /> |
||||||
<attr format="color" name="line_color_default"/>//验证码下面线的默认颜色 |
|
||||||
<attr format="color" name="line_color_focus"/>//验证码下面线选中后的颜色 |
|
||||||
</declare-styleable> |
</declare-styleable> |
||||||
|
|
||||||
</resources> |
</resources> |
Loading…
Reference in new issue