可展开列表,听到这几个字的时候也许你就会问了,为啥要用 RecyclerView,用Android提供的 ExpandableListView不是更好吗?是的,ExpandableListView是很轻松就可以实现,但是,我要告诉你,我就是喜欢用RecyclerView ……
好了,不再废话了,这里只是想用RecyclerView实现ExpandableListView的效果,提供一种实现方法和思路,其实很简单,就一句话,展开--插入一行、收起--删除一行。
先上效果图,用的模拟器,有点卡,真机测试很流畅,为了便于区分,上了点色,样子有点丑
说一下实现思路:
* 列表组成:主要分成两个布局,默认展示的为父布局,点击父布局,在父布局的下方插入一行(子布局);
*展开效果:点击Item,插入一行数据的同时,该item下方的item向下滚动,也就是展开效果;
*动画效果:咳咳…… RecyclerView自带这种渐变的动画效果(知道我为啥喜欢RecyclerView了吧,哈哈),ListView自身是没有这种效果的。
以上也就是简单的实现思路,下面上码。
一大波代码来袭
首先是实体类,用来封装模拟数据
- /**
- * Created by hbh on 2017/4/20.
- * 实体类,模拟数据
- */
- public class DataBean {
- public static final int PARENT_ITEM = 0;//父布局
- public static final int CHILD_ITEM = 1;//子布局
- private int type;// 显示类型
- private boolean isExpand;// 是否展开
- private DataBean childBean;
- private String ID;
- private String parentLeftTxt;
- private String parentRightTxt;
- private String childLeftTxt;
- private String childRightTxt;
- public String getParentLeftTxt() {
- return parentLeftTxt;
- }
- public void setParentLeftTxt(String parentLeftTxt) {
- this.parentLeftTxt = parentLeftTxt;
- }
- public String getChildRightTxt() {
- return childRightTxt;
- }
- public void setChildRightTxt(String childRightTxt) {
- this.childRightTxt = childRightTxt;
- }
- public String getChildLeftTxt() {
- return childLeftTxt;
- }
- public void setChildLeftTxt(String childLeftTxt) {
- this.childLeftTxt = childLeftTxt;
- }
- public String getParentRightTxt() {
- return parentRightTxt;
- }
- public void setParentRightTxt(String parentRightTxt) {
- this.parentRightTxt = parentRightTxt;
- }
- public int getType() {
- return type;
- }
- public void setType(int type) {
- this.type = type;
- }
- public boolean isExpand() {
- return isExpand;
- }
- public void setExpand(boolean expand) {
- isExpand = expand;
- }
- public DataBean getChildBean() {
- return childBean;
- }
- public void setChildBean(DataBean childBean) {
- this.childBean = childBean;
- }
- public String getID() {
- return ID;
- }
- public void setID(String ID) {
- this.ID = ID;
- }
- }
/**
* Created by hbh on 2017/4/20.
* 实体类,模拟数据
*/
public class DataBean {
public static final int PARENT_ITEM = 0;//父布局
public static final int CHILD_ITEM = 1;//子布局
private int type;// 显示类型
private boolean isExpand;// 是否展开
private DataBean childBean;
private String ID;
private String parentLeftTxt;
private String parentRightTxt;
private String childLeftTxt;
private String childRightTxt;
public String getParentLeftTxt() {
return parentLeftTxt;
}
public void setParentLeftTxt(String parentLeftTxt) {
this.parentLeftTxt = parentLeftTxt;
}
public String getChildRightTxt() {
return childRightTxt;
}
public void setChildRightTxt(String childRightTxt) {
this.childRightTxt = childRightTxt;
}
public String getChildLeftTxt() {
return childLeftTxt;
}
public void setChildLeftTxt(String childLeftTxt) {
this.childLeftTxt = childLeftTxt;
}
public String getParentRightTxt() {
return parentRightTxt;
}
public void setParentRightTxt(String parentRightTxt) {
this.parentRightTxt = parentRightTxt;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public boolean isExpand() {
return isExpand;
}
public void setExpand(boolean expand) {
isExpand = expand;
}
public DataBean getChildBean() {
return childBean;
}
public void setChildBean(DataBean childBean) {
this.childBean = childBean;
}
public String getID() {
return ID;
}
public void setID(String ID) {
this.ID = ID;
}
}
- <?xml version="1.0" encoding= "utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/activity_main"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.hbh.cl.expandrecyclerviewdemo.MainActivity">
- <android.support.v7.widget.RecyclerView
- android:id="@+id/recycle_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars="vertical"
- android:background="@color/white"
- android:paddingTop="5dp">
- </android.support.v7.widget.RecyclerView>
- </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.hbh.cl.expandrecyclerviewdemo.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:background="@color/white"
android:paddingTop="5dp">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
- public class MainActivity extends AppCompatActivity {
- private RecyclerView mRecyclerView;
- private List<DataBean> dataBeanList;
- private DataBean dataBean;
- private RecyclerAdapter mAdapter;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mRecyclerView = (RecyclerView) findViewById(R.id.recycle_view);
- initData();
- }
- /**
- * 模拟数据
- */
- private void initData(){
- dataBeanList = new ArrayList<>();
- for (int i = 1; i <= 50; i++) {
- dataBean = new DataBean();
- dataBean.setID(i+"");
- dataBean.setType(0);
- dataBean.setParentLeftTxt("父--"+i);
- dataBean.setParentRightTxt("父内容--"+i);
- dataBean.setChildLeftTxt("子--"+i);
- dataBean.setChildRightTxt("子内容--"+i);
- dataBean.setChildBean(dataBean);
- dataBeanList.add(dataBean);
- }
- setData();
- }
- private void setData(){
- mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
- mAdapter = new RecyclerAdapter(this,dataBeanList);
- mRecyclerView.setAdapter(mAdapter);
- //滚动监听
- mAdapter.setOnScrollListener(new RecyclerAdapter.OnScrollListener() {
- @Override
- public void scrollTo(int pos) {
- mRecyclerView.scrollToPosition(pos);
- }
- });
- }
- }
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private List<DataBean> dataBeanList;
private DataBean dataBean;
private RecyclerAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycle_view);
initData();
}
/**
* 模拟数据
*/
private void initData(){
dataBeanList = new ArrayList<>();
for (int i = 1; i <= 50; i++) {
dataBean = new DataBean();
dataBean.setID(i+"");
dataBean.setType(0);
dataBean.setParentLeftTxt("父--"+i);
dataBean.setParentRightTxt("父内容--"+i);
dataBean.setChildLeftTxt("子--"+i);
dataBean.setChildRightTxt("子内容--"+i);
dataBean.setChildBean(dataBean);
dataBeanList.add(dataBean);
}
setData();
}
private void setData(){
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new RecyclerAdapter(this,dataBeanList);
mRecyclerView.setAdapter(mAdapter);
//滚动监听
mAdapter.setOnScrollListener(new RecyclerAdapter.OnScrollListener() {
@Override
public void scrollTo(int pos) {
mRecyclerView.scrollToPosition(pos);
}
});
}
}
再有就是自定义Item点击监听接口,一个展开,一个收起
- /**
- * Created by hbh on 2017/4/20.
- * 父布局Item点击监听接口
- */
- public interface ItemClickListener {
- /**
- * 展开子Item
- * @param bean
- */
- void onExpandChildren(DataBean bean);
- /**
- * 隐藏子Item
- * @param bean
- */
- void onHideChildren(DataBean bean);
- }
/**
* Created by hbh on 2017/4/20.
* 父布局Item点击监听接口
*/
public interface ItemClickListener {
/**
* 展开子Item
* @param bean
*/
void onExpandChildren(DataBean bean);
/**
* 隐藏子Item
* @param bean
*/
void onHideChildren(DataBean bean);
}
- /**
- * Created by hbh on 2017/4/20.
- * 适配器
- */
- public class RecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> {
- private Context context;
- private List<DataBean> dataBeanList;
- private LayoutInflater mInflater;
- private OnScrollListener mOnScrollListener;
- public RecyclerAdapter(Context context, List<DataBean> dataBeanList) {
- this.context = context;
- this.dataBeanList = dataBeanList;
- this.mInflater = LayoutInflater.from(context);
- }
- @Override
- public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- View view = null;
- switch (viewType){
- case DataBean.PARENT_ITEM:
- view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);
- return new ParentViewHolder(context, view);
- case DataBean.CHILD_ITEM:
- view = mInflater.inflate(R.layout.recycleview_item_child, parent, false);
- return new ChildViewHolder(context, view);
- default:
- view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);
- return new ParentViewHolder(context, view);
- }
- }
- /**
- * 根据不同的类型绑定View
- * @param holder
- * @param position
- */
- @Override
- public void onBindViewHolder(BaseViewHolder holder, int position) {
- switch (getItemViewType(position)){
- case DataBean.PARENT_ITEM:
- ParentViewHolder parentViewHolder = (ParentViewHolder) holder;
- parentViewHolder.bindView(dataBeanList.get(position), position, itemClickListener);
- break;
- case DataBean.CHILD_ITEM:
- ChildViewHolder childViewHolder = (ChildViewHolder) holder;
- childViewHolder.bindView(dataBeanList.get(position), position);
- break;
- }
- }
- @Override
- public int getItemCount() {
- return dataBeanList.size();
- }
- @Override
- public int getItemViewType(int position) {
- return dataBeanList.get(position).getType();
- }
- private ItemClickListener itemClickListener = new ItemClickListener() {
- @Override
- public void onExpandChildren(DataBean bean) {
- int position = getCurrentPosition(bean.getID());//确定当前点击的item位置
- DataBean children = getChildDataBean(bean);//获取要展示的子布局数据对象,注意区分onHideChildren方法中的getChildBean()。
- if (children == null) {
- return;
- }
- add(children, position + 1);//在当前的item下方插入
- if (position == dataBeanList.size() - 2 && mOnScrollListener != null) { //如果点击的item为最后一个
- mOnScrollListener.scrollTo(position + 1);//向下滚动,使子布局能够完全展示
- }
- }
- @Override
- public void onHideChildren(DataBean bean) {
- int position = getCurrentPosition(bean.getID());//确定当前点击的item位置
- DataBean children = bean.getChildBean();//获取子布局对象
- if (children == null) {
- return;
- }
- remove(position + 1);//删除
- if (mOnScrollListener != null) {
- mOnScrollListener.scrollTo(position);
- }
- }
- };
- /**
- * 在父布局下方插入一条数据
- * @param bean
- * @param position
- */
- public void add(DataBean bean, int position) {
- dataBeanList.add(position, bean);
- notifyItemInserted(position);
- }
- /**
- *移除子布局数据
- * @param position
- */
- protected void remove(int position) {
- dataBeanList.remove(position);
- notifyItemRemoved(position);
- }
- /**
- * 确定当前点击的item位置并返回
- * @param uuid
- * @return
- */
- protected int getCurrentPosition(String uuid) {
- for (int i = 0; i < dataBeanList.size(); i++) {
- if (uuid.equalsIgnoreCase(dataBeanList.get(i).getID())) {
- return i;
- }
- }
- return -1;
- }
- /**
- * 封装子布局数据对象并返回
- * 注意,此处只是重新封装一个DataBean对象,为了标注Type为子布局数据,进而展开,展示数据
- * 要和onHideChildren方法里的getChildBean()区分开来
- * @param bean
- * @return
- */
- private DataBean getChildDataBean(DataBean bean){
- DataBean child = new DataBean();
- child.setType(1);
- child.setParentLeftTxt(bean.getParentLeftTxt());
- child.setParentRightTxt(bean.getParentRightTxt());
- child.setChildLeftTxt(bean.getChildLeftTxt());
- child.setChildRightTxt(bean.getChildRightTxt());
- return child;
- }
- /**
- * 滚动监听接口
- */
- public interface OnScrollListener{
- void scrollTo(int pos);
- }
- public void setOnScrollListener(OnScrollListener onScrollListener){
- this.mOnScrollListener = onScrollListener;
- }
- }
/**
* Created by hbh on 2017/4/20.
* 适配器
*/
public class RecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> {
private Context context;
private List<DataBean> dataBeanList;
private LayoutInflater mInflater;
private OnScrollListener mOnScrollListener;
public RecyclerAdapter(Context context, List<DataBean> dataBeanList) {
this.context = context;
this.dataBeanList = dataBeanList;
this.mInflater = LayoutInflater.from(context);
}
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
switch (viewType){
case DataBean.PARENT_ITEM:
view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);
return new ParentViewHolder(context, view);
case DataBean.CHILD_ITEM:
view = mInflater.inflate(R.layout.recycleview_item_child, parent, false);
return new ChildViewHolder(context, view);
default:
view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);
return new ParentViewHolder(context, view);
}
}
/**
* 根据不同的类型绑定View
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
switch (getItemViewType(position)){
case DataBean.PARENT_ITEM:
ParentViewHolder parentViewHolder = (ParentViewHolder) holder;
parentViewHolder.bindView(dataBeanList.get(position), position, itemClickListener);
break;
case DataBean.CHILD_ITEM:
ChildViewHolder childViewHolder = (ChildViewHolder) holder;
childViewHolder.bindView(dataBeanList.get(position), position);
break;
}
}
@Override
public int getItemCount() {
return dataBeanList.size();
}
@Override
public int getItemViewType(int position) {
return dataBeanList.get(position).getType();
}
private ItemClickListener itemClickListener = new ItemClickListener() {
@Override
public void onExpandChildren(DataBean bean) {
int position = getCurrentPosition(bean.getID());//确定当前点击的item位置
DataBean children = getChildDataBean(bean);//获取要展示的子布局数据对象,注意区分onHideChildren方法中的getChildBean()。
if (children == null) {
return;
}
add(children, position + 1);//在当前的item下方插入
if (position == dataBeanList.size() - 2 && mOnScrollListener != null) { //如果点击的item为最后一个
mOnScrollListener.scrollTo(position + 1);//向下滚动,使子布局能够完全展示
}
}
@Override
public void onHideChildren(DataBean bean) {
int position = getCurrentPosition(bean.getID());//确定当前点击的item位置
DataBean children = bean.getChildBean();//获取子布局对象
if (children == null) {
return;
}
remove(position + 1);//删除
if (mOnScrollListener != null) {
mOnScrollListener.scrollTo(position);
}
}
};
/**
* 在父布局下方插入一条数据
* @param bean
* @param position
*/
public void add(DataBean bean, int position) {
dataBeanList.add(position, bean);
notifyItemInserted(position);
}
/**
*移除子布局数据
* @param position
*/
protected void remove(int position) {
dataBeanList.remove(position);
notifyItemRemoved(position);
}
/**
* 确定当前点击的item位置并返回
* @param uuid
* @return
*/
protected int getCurrentPosition(String uuid) {
for (int i = 0; i < dataBeanList.size(); i++) {
if (uuid.equalsIgnoreCase(dataBeanList.get(i).getID())) {
return i;
}
}
return -1;
}
/**
* 封装子布局数据对象并返回
* 注意,此处只是重新封装一个DataBean对象,为了标注Type为子布局数据,进而展开,展示数据
* 要和onHideChildren方法里的getChildBean()区分开来
* @param bean
* @return
*/
private DataBean getChildDataBean(DataBean bean){
DataBean child = new DataBean();
child.setType(1);
child.setParentLeftTxt(bean.getParentLeftTxt());
child.setParentRightTxt(bean.getParentRightTxt());
child.setChildLeftTxt(bean.getChildLeftTxt());
child.setChildRightTxt(bean.getChildRightTxt());
return child;
}
/**
* 滚动监听接口
*/
public interface OnScrollListener{
void scrollTo(int pos);
}
public void setOnScrollListener(OnScrollListener onScrollListener){
this.mOnScrollListener = onScrollListener;
}
}
还有两个对应的 ParentViewHolder 和 ChildViewHolder
- /**
- * Created by hbh on 2017/4/20.
- * 父布局ViewHolder
- */
- public class ParentViewHolder extends BaseViewHolder {
- private Context mContext;
- private View view;
- private RelativeLayout containerLayout;
- private TextView parentLeftView;
- private TextView parentRightView;
- private ImageView expand;
- private View parentDashedView;
- public ParentViewHolder(Context context, View itemView) {
- super(itemView);
- this.mContext = context;
- this.view = itemView;
- }
- public void bindView(final DataBean dataBean, final int pos, final ItemClickListener listener){
- containerLayout = (RelativeLayout) view.findViewById(R.id.container);
- parentLeftView = (TextView) view.findViewById(R.id.parent_left_text);
- parentRightView = (TextView) view.findViewById(R.id.parent_right_text);
- expand = (ImageView) view.findViewById(R.id.expend);
- parentDashedView = view.findViewById(R.id.parent_dashed_view);
- RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) expand
- .getLayoutParams();
- expand.setLayoutParams(params);
- parentLeftView.setText(dataBean.getParentLeftTxt());
- parentRightView.setText(dataBean.getParentRightTxt());
- if (dataBean.isExpand()) {
- expand.setRotation(90);
- parentDashedView.setVisibility(View.INVISIBLE);
- } else {
- expand.setRotation(0);
- parentDashedView.setVisibility(View.VISIBLE);
- }
- //父布局OnClick监听
- containerLayout.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (listener != null) {
- if (dataBean.isExpand()) {
- listener.onHideChildren(dataBean);
- parentDashedView.setVisibility(View.VISIBLE);
- dataBean.setExpand(false);
- rotationExpandIcon(90, 0);
- } else {
- listener.onExpandChildren(dataBean);
- parentDashedView.setVisibility(View.INVISIBLE);
- dataBean.setExpand(true);
- rotationExpandIcon(0, 90);
- }
- }
- }
- });
- }
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- private void rotationExpandIcon(float from, float to) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- ValueAnimator valueAnimator = ValueAnimator.ofFloat(from, to);//属性动画
- valueAnimator.setDuration(500);
- valueAnimator.setInterpolator(new DecelerateInterpolator());
- valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- expand.setRotation((Float) valueAnimator.getAnimatedValue());
- }
- });
- valueAnimator.start();
- }
- }
- }
/**
* Created by hbh on 2017/4/20.
* 父布局ViewHolder
*/
public class ParentViewHolder extends BaseViewHolder {
private Context mContext;
private View view;
private RelativeLayout containerLayout;
private TextView parentLeftView;
private TextView parentRightView;
private ImageView expand;
private View parentDashedView;
public ParentViewHolder(Context context, View itemView) {
super(itemView);
this.mContext = context;
this.view = itemView;
}
public void bindView(final DataBean dataBean, final int pos, final ItemClickListener listener){
containerLayout = (RelativeLayout) view.findViewById(R.id.container);
parentLeftView = (TextView) view.findViewById(R.id.parent_left_text);
parentRightView = (TextView) view.findViewById(R.id.parent_right_text);
expand = (ImageView) view.findViewById(R.id.expend);
parentDashedView = view.findViewById(R.id.parent_dashed_view);
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) expand
.getLayoutParams();
expand.setLayoutParams(params);
parentLeftView.setText(dataBean.getParentLeftTxt());
parentRightView.setText(dataBean.getParentRightTxt());
if (dataBean.isExpand()) {
expand.setRotation(90);
parentDashedView.setVisibility(View.INVISIBLE);
} else {
expand.setRotation(0);
parentDashedView.setVisibility(View.VISIBLE);
}
//父布局OnClick监听
containerLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
if (dataBean.isExpand()) {
listener.onHideChildren(dataBean);
parentDashedView.setVisibility(View.VISIBLE);
dataBean.setExpand(false);
rotationExpandIcon(90, 0);
} else {
listener.onExpandChildren(dataBean);
parentDashedView.setVisibility(View.INVISIBLE);
dataBean.setExpand(true);
rotationExpandIcon(0, 90);
}
}
}
});
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void rotationExpandIcon(float from, float to) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(from, to);//属性动画
valueAnimator.setDuration(500);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
expand.setRotation((Float) valueAnimator.getAnimatedValue());
}
});
valueAnimator.start();
}
}
}
- /**
- * Created by hbh on 2017/4/20.
- * 子布局ViewHolder
- */
- public class ChildViewHolder extends BaseViewHolder {
- private Context mContext;
- private View view;
- private TextView childLeftText;
- private TextView childRightText;
- public ChildViewHolder(Context context, View itemView) {
- super(itemView);
- this.mContext = context;
- this.view = itemView;
- }
- public void bindView(final DataBean dataBean, final int pos){
- childLeftText = (TextView) view.findViewById(R.id.child_left_text);
- childRightText = (TextView) view.findViewById(R.id.child_right_text);
- childLeftText.setText(dataBean.getChildLeftTxt());
- childRightText.setText(dataBean.getChildRightTxt());
- }
- }
/**
* Created by hbh on 2017/4/20.
* 子布局ViewHolder
*/
public class ChildViewHolder extends BaseViewHolder {
private Context mContext;
private View view;
private TextView childLeftText;
private TextView childRightText;
public ChildViewHolder(Context context, View itemView) {
super(itemView);
this.mContext = context;
this.view = itemView;
}
public void bindView(final DataBean dataBean, final int pos){
childLeftText = (TextView) view.findViewById(R.id.child_left_text);
childRightText = (TextView) view.findViewById(R.id.child_right_text);
childLeftText.setText(dataBean.getChildLeftTxt());
childRightText.setText(dataBean.getChildRightTxt());
}
}
OVER,以上就是主要的代码,大部分都贴上了,很简单。
总的来说就是 通过增加和删除 再加上动画效果 来模拟列表的展开和收起,在这里抛砖引玉,如有更好的实现方法或方式,还望各位猿友们不吝赐教,文章如有表述不当,还请指正。