您的位置:首页 > 移动开发 > Android开发

Android 自定义HorizontalScrollView实现二级菜单

2017-12-25 16:53 549 查看

Android 自定义HorizontalScrollView实现二级菜单

首先感谢一篇博客对本人的指导,Android 自定义控件打造史上最简单的侧滑菜单 ,十分感谢。

最近有一个项目需求是这样的,首先有两个纵向的List,也就是二级菜单,点击主List的项目会打开对应副List中的项目,然后滑动可以隐藏掉主List,同时副List的文字会居中显示。

先来看看效果



MyScrollView

首先重写自定View继承HorizontalScrollView,其中HorizontalScrollView有几个很重要的方法,分别是scrollTo, scrollBy, smoothScrollTo, smoothScrollBy,这里我们用到smoothScrollTo(x, y),即平滑地滑动到,注意,x和y是相对于HorizontalScrollView而不是屏幕。这里我们还要重写onTouchEvent,当手指离开屏幕时判断主List被移出了多少,当移出超过一半时完全显示,少于一半时隐藏。

public class MyScrollView extends HorizontalScrollView {
/**
* 屏幕宽度
*/
private int screenWidth;
/**
* 主list的宽度
*/
private int chiefListWidth;
private int halfChiefWidth;

private boolean once = true;
/**
* chiefList是否打开
*/
private boolean isOpen = false;

public MyScrollView(Context context) {
this(context, null);
}

public MyScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

//获取屏幕宽度
screenWidth = getResources().getDisplayMetrics().widthPixels;

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 显示的设置一个宽度
*/
if (once) {
LinearLayout wrapper = (LinearLayout) getChildAt(0);
RecyclerView chiefList = (RecyclerView) wrapper.getChildAt(0);
RecyclerView adjunctList = (RecyclerView) wrapper.getChildAt(1);

chiefListWidth = screenWidth / 2;
halfChiefWidth = chiefListWidth / 2;
//设置chiefList的宽度为屏幕的一半
chiefList.getLayoutParams().width = chiefListWidth;
//设置adjunctList的宽度为屏幕宽
adjunctList.getLayoutParams().width = screenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
// 先显示ChiefList
this.scrollTo(0, 0);
once = false;
}
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
// Up时,进行判断,如果显示区域大于ChiefList宽度一半则完全显示,否则隐藏
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();
if (scrollX > halfChiefWidth) {
this.smoothScrollTo(chiefListWidth, 0);
isOpen = false;
} else {
this.smoothScrollTo(0, 0);
isOpen = true;
}
//将状态回调出去
if (onChiefListOpenListener != null) {
onChiefListOpenListener.onChiefListOpen(isOpen);
}
return true;
}
return super.onTouchEvent(ev);
}

interface OnChiefListOpenListener {
void onChiefListOpen(boolean isOpen);
}

private OnChiefListOpenListener onChiefListOpenListener;

public void setOnChiefListOpenListener(OnChiefListOpenListener onChiefListOpenListener) {
this.onChiefListOpenListener = onChiefListOpenListener;
}
}


这里我们还写了个OnChiefListOpenListener接口,其作用是将主List是否在显示的状态回调出去供Adapter使用,因为副List的文本对齐是要用到的。

MyAdapter

RecyclerView要用到的Adapter,这里我们只简单地显示文本,因为主List和副List都用同一个Adapter,故构造时还需传递一个isChief参数。参数isOpen指明当前主List是否打开,如果打开则更新副List让文本居中显示,否则靠左显示。

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

private Context context;
private List<String> datas;
private boolean isChief;
private boolean isOpen = true;

public MyAdapter(Context context, List<String> datas, boolean isChief) {
this.context = context;
this.datas = datas;
this.isChief = isChief;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_double_list, parent, false);
return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.tvMsg.setText(datas.get(position));

if (!isChief) {
//副List
if (isOpen) {
//主List打开,靠左显示
holder.tvMsg.setGravity(Gravity.LEFT);
} else {
//主List关闭,居中显示
holder.tvMsg.setGravity(Gravity.CENTER_HORIZONTAL);
}
}

holder.tvMsg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//将点击事件传递给Activity
if (onItemClickListener != null) {
onItemClickListener.onItemClick(position);
}
}
});

}

@Override
public int getItemCount() {
return datas == null ? 0 : datas.size();
}

class ViewHolder extends RecyclerView.ViewHolder {

TextView tvMsg;

public ViewHolder(View itemView) {
super(itemView);
tvMsg = itemView.findViewById(R.id.tv_msg);
}
}

public void changeDatas(List<String> datas) {
this.datas = datas;
notifyDataSetChanged();
}

public void changeOpen(boolean isOpen) {
this.isOpen = isOpen;
notifyDataSetChanged();
}

interface OnItemClickListener {
void onItemClick(int position);
}

private OnItemClickListener onItemClickListener;

public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}


MainActivity

Activity就没什么好讲的了,主要是两个RecyclerView,两个Adapter,三个数据集,其中一个数据集是Map,用来指明主List中每个item对应的副List,相当于一个二维数组。

public class MainActivity extends AppCompatActivity {

private RecyclerView chiefRecyclerView;
private MyAdapter chiefAdapter;
private List<String> chiefDatas;

private RecyclerView adjunctRecyclerView;
private MyAdapter adjunctAdapter;
private List<String> adjunctDatas;

/**
* 主List中每个item对应的副List,相当于一个二维数组
*/
private Map<String, List<String>> dataMap;

private MyScrollView myScrollView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

chiefRecyclerView = findViewById(R.id.lv_chief);
adjunctRecyclerView = findViewById(R.id.lv_adjunct);
myScrollView = findViewById(R.id.my_scroll_view);

//造数据
chiefDatas = new ArrayList<>();
adjunctDatas = new ArrayList<>();
dataMap = new HashMap<>();
for (int i = 0; i < 20; i++) {
String select = "select" + i;
chiefDatas.add(select);
List<String> tempList = new ArrayList<>();
for (int j = 0; j < 5; j++) {
String option = "option" + i + j;
tempList.add(option);
}
dataMap.put(select, tempList);
}
adjunctDatas = dataMap.get("select0");

//主ListAdapter
chiefAdapter = new MyAdapter(this, chiefDatas, true);
chiefAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position) {
//变换副List中的数据
adjunctDatas = dataMap.get(chiefDatas.get(position));
adjunctAdapter.changeDatas(adjunctDatas);
}
});

//副ListAdapter
adjunctAdapter = new MyAdapter(this, adjunctDatas, false);
adjunctAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
@Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this, adjunctDatas.get(position), Toast.LENGTH_SHORT).show();
}
});

//ScrollView中主List的开启状态变化
myScrollView.setOnChiefListOpenListener(new MyScrollView.OnChiefListOpenListener() {
@Override
public void onChiefListOpen(boolean isOpen) {
adjunctAdapter.changeOpen(isOpen);
}
});

chiefRecyclerView.setAdapter(chiefAdapter);
adjunctRecyclerView.setAdapter(adjunctAdapter);
chiefRecyclerView.setLayoutManager(new LinearLayoutManager(this));
adjunctRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
}


布局文件

这里主要是activity的布局文件,至于item_double_list主要是一个TextView这里就不粘了。

<?xml version="1.0" encoding="utf-8"?>
<com.dongyang.doublelistview2.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/my_scroll_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
tools:context="com.dongyang.doublelistview2.MainActivity">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">

<android.support.v7.widget.RecyclerView
android:id="@+id/lv_chief"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="@color/colorAccent" />

<android.support.v7.widget.RecyclerView

9395
android:id="@+id/lv_adjunct"
android:layout_width="200dp"
android:layout_height="match_parent"
android:background="@color/colorPrimary" />
</LinearLayout>

</com.dongyang.doublelistview2.MyScrollView>


到这里一个可以滑动的二级菜单就完成了,谢谢你的观看。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android
相关文章推荐