效果图:
在build中引用RecycleView
//引入recycleView
implementation 'androidx.recyclerview:recyclerview:1.2.0-beta01'
两种方式
一、自定义 左滑菜单帮助类 ItemSlideHelper
/**
* 左滑菜单帮助类
*/
public class ItemSlideHelper implements RecyclerView.OnItemTouchListener, GestureDetector.OnGestureListener {
private final int DEFAULT_DURATION = 200;
private View mTargetView;
private int mActivePointerId;
private int mTouchSlop;
private int mMaxVelocity;
private int mMinVelocity;
private int mLastX;
private int mLastY;
private boolean mIsDragging;
private Animator mExpandAndCollapseAnim;
private GestureDetectorCompat mGestureDetector;
private Callback mCallback;
public ItemSlideHelper(Context context, Callback callback) {
this.mCallback = callback;
//手势用于处理fling
mGestureDetector = new GestureDetectorCompat(context, this);
ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
mMaxVelocity = configuration.getScaledMaximumFlingVelocity();
mMinVelocity = configuration.getScaledMinimumFlingVelocity();
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
int action = MotionEventCompat.getActionMasked(e);
int x = (int) e.getX();
int y = (int) e.getY();
//如果RecyclerView滚动状态不是空闲targetView不是空
if (rv.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
if (mTargetView != null) {
//隐藏已经打开
smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);
mTargetView = null;
}
return false;
}
//如果正在运行动画 ,直接拦截什么都不做
if (mExpandAndCollapseAnim != null && mExpandAndCollapseAnim.isRunning()) {
return true;
}
boolean needIntercept = false;
switch (action) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = MotionEventCompat.getPointerId(e, 0);
mLastX = (int) e.getX();
mLastY = (int) e.getY();
/*
* 如果之前有一个已经打开的项目,当此次点击事件没有发生在右侧的菜单中则返回TRUE,
* 如果点击的是右侧菜单那么返回FALSE这样做的原因是因为菜单需要响应Onclick
* */
if (mTargetView != null) {
return !inView(x, y);
}
//查找需要显示菜单的view;
mTargetView = mCallback.findTargetView(x, y);
break;
case MotionEvent.ACTION_MOVE:
int deltaX = (x - mLastX);
int deltaY = (y - mLastY);
if (Math.abs(deltaY) > Math.abs(deltaX))
return false;
//如果移动距离达到要求,则拦截
needIntercept = mIsDragging = mTargetView != null && Math.abs(deltaX) >= mTouchSlop;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
/*
* 走这是因为没有发生过拦截事件
* */
if (isExpanded()) {
if (inView(x, y)) {
// 如果走这那行这个ACTION_UP的事件会发生在右侧的菜单中
} else {
//拦截事件,防止targetView执行onClick事件
needIntercept = true;
}
//折叠菜单
smoothHorizontalExpandOrCollapse(DEFAULT_DURATION / 2);
}
mTargetView = null;
break;
}
return needIntercept;
}
private boolean isExpanded() {
return mTargetView != null && mTargetView.getScrollX() == getHorizontalRange();
}
private boolean isCollapsed() {
return mTargetView != null && mTargetView.getScrollX() == 0;
}
/*
* 根据targetView的scrollX计算出targetView的偏移,这样能够知道这个point
* 是在右侧的菜单中
* */
private boolean inView(int x, int y) {
if (mTargetView == null)
return false;
int scrollX = mTargetView.getScrollX();
int left = mTargetView.getWidth() - scrollX;
int top = mTargetView.getTop();
int right = left + getHorizontalRange();
int bottom = mTargetView.getBottom();
Rect rect = new Rect(left, top, right, bottom);
return rect.contains(x, y);
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
if (mExpandAndCollapseAnim != null && mExpandAndCollapseAnim.isRunning() || mTargetView == null)
return;
//如果要响应fling事件设置将mIsDragging设为false
if (mGestureDetector.onTouchEvent(e)) {
mIsDragging = false;
return;
}
int x = (int) e.getX();
int y = (int) e.getY();
int action = MotionEventCompat.getActionMasked(e);
switch (action) {
case MotionEvent.ACTION_DOWN:
//RecyclerView 不会转发这个Down事件
break;
case MotionEvent.ACTION_MOVE:
int deltaX = (int) (mLastX - e.getX());
if (mIsDragging) {
horizontalDrag(deltaX);
}
mLastX = x;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mIsDragging) {
if (!smoothHorizontalExpandOrCollapse(0) && isCollapsed())
mTargetView = null;
mIsDragging = false;
}
break;
}
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
/**
* 根据touch事件来滚动View的scrollX
*
* @param delta
*/
private void horizontalDrag(int delta) {
int scrollX = mTargetView.getScrollX();
int scrollY = mTargetView.getScrollY();
if ((scrollX + delta) <= 0) {
mTargetView.scrollTo(0, scrollY);
return;
}
int horRange = getHorizontalRange();
scrollX += delta;
if (Math.abs(scrollX) < horRange) {
mTargetView.scrollTo(scrollX, scrollY);
} else {
mTargetView.scrollTo(horRange, scrollY);
}
}
/**
* 根据当前scrollX的位置判断是展开还是折叠
*
* @param velocityX 如果不等于0那么这是一次fling事件,否则是一次ACTION_UP或者ACTION_CANCEL
*/
private boolean smoothHorizontalExpandOrCollapse(float velocityX) {
int scrollX = mTargetView.getScrollX();
int scrollRange = getHorizontalRange();
if (mExpandAndCollapseAnim != null)
return false;
int to = 0;
int duration = DEFAULT_DURATION;
if (velocityX == 0) {
//如果已经展一半,平滑展开
if (scrollX > scrollRange / 2) {
to = scrollRange;
}
} else {
if (velocityX > 0)
to = 0;
else
to = scrollRange;
duration = (int) ((1.f - Math.abs(velocityX) / mMaxVelocity) * DEFAULT_DURATION);
}
if (to == scrollX)
return false;
mExpandAndCollapseAnim = ObjectAnimator.ofInt(mTargetView, "scrollX", to);
mExpandAndCollapseAnim.setDuration(duration);
mExpandAndCollapseAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mExpandAndCollapseAnim = null;
if (isCollapsed())
mTargetView = null;
}
@Override
public void onAnimationCancel(Animator animation) {
//onAnimationEnd(animation);
mExpandAndCollapseAnim = null;
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mExpandAndCollapseAnim.start();
return true;
}
public int getHorizontalRange() {
RecyclerView.ViewHolder viewHolder = mCallback.getChildViewHolder(mTargetView);
return mCallback.getHorizontalRange(viewHolder);
}
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (Math.abs(velocityX) > mMinVelocity && Math.abs(velocityX) < mMaxVelocity) {
if (!smoothHorizontalExpandOrCollapse(velocityX)) {
if (isCollapsed())
mTargetView = null;
return true;
}
}
return false;
}
/**
* 左滑菜单Callback
*/
public interface Callback {
int getHorizontalRange(RecyclerView.ViewHolder holder);
RecyclerView.ViewHolder getChildViewHolder(View childView);
View findTargetView(float x, float y);
}
}
2.该类在Adapter中使用
/**
* 消息adapter
* <p/>
* -->特别注意extends后面Adapter<>里面要写自己定义的ViewHolder
*/
public class MsgRemindAdapter extends RecyclerView.Adapter<MsgRemindAdapter.RemindViewHolder>
implements ItemSlideHelper.Callback {
private Context context;
private List<MsgVo> mDatas = new ArrayList<MsgVo>();
private RecyclerView mRecyclerView;
public MsgRemindAdapter(Context context, List<MsgVo> mDatas) {
this.context = context;
this.mDatas = mDatas;
}
@Override
public RemindViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_msg_remind, parent, false);
return new RemindViewHolder(view);
}
/**
* 将recyclerView绑定Slide事件
*
* @param recyclerView
*/
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecyclerView = recyclerView;
mRecyclerView.addOnItemTouchListener(new ItemSlideHelper(mRecyclerView.getContext(), this));
}
@Override
public void onBindViewHolder(final RemindViewHolder holder, final int position) {
/**
* 消息状态
*/
if (mDatas.get(position).isChecked()) {
holder.llMsgRemindMain.setBackgroundColor(ContextCompat.getColor(context, R.color.yellow));
holder.tvMsgRemindCheck.setText("删除标记");
} else {
holder.llMsgRemindMain.setBackgroundColor(ContextCompat.getColor(context, R.color.touming));
holder.tvMsgRemindCheck.setText("标记已读");
}
//消息标题
holder.tvRemindTitle.setText(mDatas.get(position).getTitle());
//消息内容
holder.tvRemindContent.setText(mDatas.get(position).getContent());
/**
* -->特别注意,敲黑板了啊!!!在执行notify的时候,取position要取holder.getAdapterPosition(),
* 消息被删除之后,他原来的position是final的,所以取到的值不准确,会报数组越界。
*/
//消息主体监听,这里我是让他添加一条数据,替换成你需要的操作即可
holder.llMsgRemindMain.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e("okhttp" ,"点击位置 position = "+position);
}
});
//标记已读监听
holder.tvMsgRemindCheck.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
boolean isCheck = mDatas.get(position).isChecked();
if (isCheck) {
mDatas.get(position).setChecked(false);
} else {
mDatas.get(position).setChecked(true);
}
notifyItemChanged(position);
}
});
//删除监听
holder.tvMsgRemindDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
removeData(position);
}
});
}
@Override
public int getItemCount() {
return mDatas.size();
}
/**
* 此方法用来计算水平方向移动的距离
*
* @param holder
* @return
*/
@Override
public int getHorizontalRange(RecyclerView.ViewHolder holder) {
if (holder.itemView instanceof LinearLayout) {
ViewGroup viewGroup = (ViewGroup) holder.itemView;
//viewGroup包含3个控件,即消息主item、标记已读、删除,返回为标记已读宽度+删除宽度
return viewGroup.getChildAt(1).getLayoutParams().width
+ viewGroup.getChildAt(2).getLayoutParams().width;
}
return 0;
}
@Override
public RecyclerView.ViewHolder getChildViewHolder(View childView) {
return mRecyclerView.getChildViewHolder(childView);
}
@Override
public View findTargetView(float x, float y) {
return mRecyclerView.findChildViewUnder(x, y);
}
/**
* 自定义的ViewHolder
*/
public class RemindViewHolder extends RecyclerView.ViewHolder {
TextView tvRemindTitle;
TextView tvRemindContent;
LinearLayout llMsgRemindMain;
TextView tvMsgRemindCheck;
TextView tvMsgRemindDelete;
public RemindViewHolder(View itemView) {
super(itemView);
tvRemindTitle = itemView.findViewById(R.id.tv_remind_title);
tvRemindContent = itemView.findViewById(R.id.tv_remind_content);
llMsgRemindMain = itemView.findViewById(R.id.ll_msg_remind_main);
tvMsgRemindCheck = itemView.findViewById(R.id.tv_msg_remind_check);
tvMsgRemindDelete = itemView.findViewById(R.id.tv_msg_remind_delete);
}
}
/**
* 删除单条数据
*
* @param position
*/
public void removeData(int position) {
mDatas.remove(position);
notifyItemRemoved(position);
}
}
3.在Activity的使用
public class ItemSideActivity extends AppCompatActivity {
private RecyclerView rvMsgRemind;
private MsgRemindAdapter msgRemindAdapter;
private List<MsgVo> mDatas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_side);
rvMsgRemind = findViewById(R.id.rv_msg_remind);
initData();
//设置布局类型为listview的LinearLayoutManager
rvMsgRemind.setLayoutManager(new LinearLayoutManager(this));
rvMsgRemind.addItemDecoration(new DividerItemDecoration(this, LinearLayout.VERTICAL));
//固定recyclerview大小
rvMsgRemind.setHasFixedSize(true);
rvMsgRemind.setAdapter(msgRemindAdapter);
}
private void initData() {
mDatas = new ArrayList<MsgVo>();
for (int i = 1; i < 11; i++) {
MsgVo vo = new MsgVo();
if (i % 2 == 1) {
vo.setChecked(true);
vo.setTitle("原始消息,已读状态" + i);
vo.setContent("乌啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦" +
"啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦" +
"啦啦啦啦啦啦啦啦啦");
} else {
vo.setChecked(false);
vo.setTitle("原始消息,未读状态");
vo.setContent("唔噜噜噜噜噜噜噜噜噜噜");
}
mDatas.add(vo);
}
msgRemindAdapter = new MsgRemindAdapter(this, mDatas);
Log.e("okhttp" ,"mDatas = "+mDatas.toString());
}
}
4.对应的两个xml
(1).item_msg_remind
<?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="72dp"
android:background="@color/white"
android:orientation="horizontal">
<!-- 消息主体,width记得match_parent,直接把后面两个布局顶出去 -->
<LinearLayout
android:id="@+id/ll_msg_remind_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="6dp">
<TextView
android:id="@+id/tv_remind_title"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="隔壁的二蛋" />
<TextView
android:id="@+id/tv_remind_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:ellipsize="end"
android:maxLines="2"
android:text="对方撤回了一条消息并砍了你的狗" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="80dp"
android:layout_height="match_parent"
android:background="#D1BA74">
<TextView
android:id="@+id/tv_msg_remind_check"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="标记已读"
android:textColor="@color/white" />
</LinearLayout>
<LinearLayout
android:layout_width="80dp"
android:layout_height="match_parent"
android:background="@color/theme_color">
<TextView
android:id="@+id/tv_msg_remind_delete"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="删除"
android:textColor="@color/white" />
</LinearLayout>
</LinearLayout>
(2).activity_item_side
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_msg_remind"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
完成
二、自定义RecycleView类,布局使用该类CustomRecyclerView
public class CustomRecyclerView extends RecyclerView {
//item的根布局
private LinearLayout itemRoot;
//上一次滑动的Item根布局
private LinearLayout itemRootLast;
//上次X轴的滑动坐标
private int mlastX = 0;
//上次Y轴的滑动坐标
private int mlastY = 0;
//滑动的最大距离
private final int MAX_WIDTH = 100;
private Context mContext;
private Scroller mScroller;
public CustomRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mContext = context;
mScroller = new Scroller(context, new LinearInterpolator(context, null));
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int maxLength = dipToPx(mContext, MAX_WIDTH);
int x = (int) event.getX();
int y = (int) event.getY();
final int position;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
//恢复上一次侧滑的ITEM
if (itemRootLast != null) {
itemRootLast.scrollTo(0, 0);
invalidate();
}
//根据点击的坐标获取那个Item被点击了
View view = findChildViewUnder(x, y);
if (view == null) {
return false;
}
final CustomAdapter.CustomViewHolder viewHolder = (CustomAdapter.CustomViewHolder) getChildViewHolder(view);
itemRootLast = itemRoot = (LinearLayout) viewHolder.textView.getParent();
position = viewHolder.getAdapterPosition();
if (mOnItemClickListener != null) {
viewHolder.deleteView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mOnItemClickListener.onClick(viewHolder.itemView, position);
}
});
}
}
break;
case MotionEvent.ACTION_MOVE: {
if (itemRoot == null) {
return false;
}
if (Math.abs(mlastX - x) > 0 && Math.abs(mlastX - x) > Math.abs(mlastY - y)) {
int scrollX = itemRoot.getScrollX();
int newScrollX = scrollX + mlastX - x;
if (newScrollX < 0) {
newScrollX = 0;
} else if (newScrollX > maxLength) {
newScrollX = maxLength;
}
itemRoot.scrollTo(newScrollX, 0);
}
}
break;
case MotionEvent.ACTION_UP: {
if (itemRoot == null) {
return false;
}
int scrollX = itemRoot.getScrollX();
int newScrollX = scrollX + mlastX - x;
if (scrollX > maxLength / 2) {
newScrollX = maxLength;
} else {
newScrollX = 0;
}
mScroller.startScroll(scrollX, 0, newScrollX - scrollX, 0);
invalidate();
}
break;
}
mlastX = x;
mlastY = y;
return super.onTouchEvent(event);
}
private int dipToPx(Context context, int dip) {
return (int) (dip * context.getResources().getDisplayMetrics().density + 0.5f);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
itemRoot.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
if (itemRootLast != null) {
itemRootLast.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
}
}
invalidate();
}
private OnItemClickListener mOnItemClickListener;
public interface OnItemClickListener {
void onClick(View view, int position);
}
public void setOnItemClickListenre(OnItemClickListener mOnItemClickListener) {
this.mOnItemClickListener = mOnItemClickListener;
}
}
2.CustomAdapter,正常创建
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {
private List<MsgVo> mDatas;
public CustomAdapter(List<MsgVo> mDatas, Context mContext) {
this.mDatas = mDatas;
}
@Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler_two, parent, false);
return new CustomViewHolder(view);
}
@Override
public void onBindViewHolder(final CustomViewHolder holder, final int position) {
holder.textView.setText(mDatas.get(position).getTitle());
}
@Override
public int getItemCount() {
return mDatas == null ? 0 : mDatas.size();
}
class CustomViewHolder extends RecyclerView.ViewHolder {
TextView textView;
TextView deleteView;
public CustomViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.item_text);
deleteView = (TextView) itemView.findViewById(R.id.item_del);
}
}
}
3.activity中使用
public class ZDYRecycleViewActivity extends AppCompatActivity {
private Context context;
private CustomRecyclerView zdyRcView;
private List<MsgVo> mDatas;
private CustomAdapter customAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zdy_recyccleview);
context = this;
zdyRcView = findViewById(R.id.zdyRcView);
initDate();
zdyRcView.setLayoutManager(new LinearLayoutManager(this));
zdyRcView.addItemDecoration(new DividerItemDecoration(this, LinearLayout.VERTICAL));
zdyRcView.setAdapter(customAdapter);
zdyRcView.setOnItemClickListenre(new CustomRecyclerView.OnItemClickListener() {
@Override
public void onClick(View view, int position) {
mDatas.remove(position);
customAdapter.notifyItemRemoved(position);
}
});
}
public void initDate() {
mDatas = new ArrayList<MsgVo>();
for (int i = 1; i < 11; i++) {
MsgVo vo = new MsgVo();
if (i % 2 == 1) {
vo.setChecked(true);
vo.setTitle("原始消息,已读状态" + i);
vo.setContent("乌啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦" +
"啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦" +
"啦啦啦啦啦啦啦啦啦");
} else {
vo.setChecked(false);
vo.setTitle("原始消息,未读状态");
vo.setContent("唔噜噜噜噜噜噜噜噜噜噜");
}
mDatas.add(vo);
}
customAdapter = new CustomAdapter(mDatas, context);
}
}
4.布局xml
(1).item_recycler_two
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/item_text"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_gravity="center"
android:gravity="center"
android:background="@color/colorAccent"
android:text="text" />
<TextView
android:id="@+id/item_del"
android:layout_width="100dp"
android:layout_height="fill_parent"
android:background="#EE2C2C"
android:gravity="center"
android:text="删除"
android:textSize="25dp" />
</LinearLayout>
(2).activity_zdy_recyccleview
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.june.recycleviewdelete.zdyRecycleView.CustomRecyclerView
android:id="@+id/zdyRcView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
完成……
如果需要可以点击Demo现在源代码(稍后上代码)
最后是交流公众号,大家可以关注一下
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/119192.html