Adroid 自定義目錄節點控件
一、效果圖如下
二、控件功能與背景
1、背景:
該控件可用於層級目錄過多的資源界面,最常見的是Android系統文件管理功能中的目錄節點顯示和點擊功能。
####2、功能:
1)、添加節點功能:
/**
* 添加節點
* @param node
*/
public void pushNode(Node node)
2)、移除棧頂節點,控件支持單節點拋,也支持多節點拋出。用戶選擇某一目錄節點時,該目錄節點之後的元素都將移除。
/**
* 拋出棧頂的節點
*/
public boolean popNode()
3)、每增加一個節點,視圖都將移動到最後一個節點的視圖。這裏用到了父類的fullScroll方法。
fullScroll(HorizontalScrollView.FOCUS_RIGHT);
三、控件分析
1、簡單分析
控件非常的簡單,我們這裏需要用到控件的橫向滑動的功能,所以這裏我們自然而然的就想到了繼承HorizontalScrollView或者HorizontalScrollView。添加的子控件也非常的簡單,TextView+ImageView組合。
2、需要用到Stack集合
節點的加入和取出屬於後進先出類型的棧,所以我們可以選擇Stack堆棧類集合,Stack 繼承自 Vector,實現一個後進先出的堆棧。
關鍵方法:
/**
* 找到棧頂元素但不移除
*/
public synchronized E peek()
/**
* 找到棧頂元素並移除
*/
public synchronized E pop()
/**
* 將元素放置到棧頂
*/
public E push(E item)
3、添加回調方法,如果設置了回調方法,用戶在拋出節點的時候會回調該方法。
public interface DirNodeListener {
void onPopNode(String nodeId);
}
四、控件源碼
/**
* @author :chezi008 on 2018/4/20 15:02
* @description :目錄節點控件
* @email :[email protected]
*/
public class DirNodeView extends HorizontalScrollView {
private String TAG = getClass().getSimpleName();
private Stack<Node> mStack;
private LinearLayout llParent;
private View.OnClickListener onClickListener;
private DirNodeListener dirNodeListener;
private boolean isScrolledLast;
public DirNodeView(Context context) {
this(context, null);
}
public DirNodeView(Context context, AttributeSet attrs) {
super(context, attrs);
initVariable();
initView();
}
public void setDirNodeListener(DirNodeListener dirNodeListener) {
this.dirNodeListener = dirNodeListener;
}
private void initVariable() {
mStack = new Stack<>();
onClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: id:" + v.getTag());
if (dirNodeListener != null) {
dirNodeListener.onPopNode((String) v.getTag());
}
popNode((String) v.getTag());
}
};
}
private void initView() {
llParent = new LinearLayout(getContext());
llParent.setOrientation(LinearLayout.HORIZONTAL);
setHorizontalScrollBarEnabled(false);
addView(llParent);
}
/**
* 添加節點
* @param node
*/
public void pushNode(Node node) {
addNodeView(node);
}
public String getNodeId() {
return mStack.peek().nodeId;
}
public Stack<Node> getStack() {
return mStack;
}
private void popNode(String id) {
int length = mStack.size();
//for循環裏面 mStack.size()是會變的
for (int i = 0; i < length; i++) {
Node node = mStack.peek();
if (node.nodeId.equals(id)) {
break;
}
popNode(node);
}
}
private void addNodeView(Node node) {
LinearLayout nodeParent = new LinearLayout(getContext());
nodeParent.setOrientation(LinearLayout.HORIZONTAL);
nodeParent.setGravity(Gravity.CENTER_VERTICAL);
int padding = DensityUtils.sp2px(getContext(), 10);
int paddingTop = DensityUtils.sp2px(getContext(), 5);
int paddingIvTop = DensityUtils.sp2px(getContext(), 7);
TextView textView = new TextView(getContext());
textView.setText(node.nodeName);
textView.setTextSize(16);
textView.setTag(node.nodeId);
textView.setPadding(padding, paddingTop, 0, paddingTop);
textView.setOnClickListener(onClickListener);
nodeParent.addView(textView);
ImageView ivRight = new ImageView(getContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
ivRight.setImageResource(R.drawable.ve_direction_right);
ivRight.setPadding(0, paddingIvTop, 0, paddingTop);
nodeParent.addView(ivRight, params);
llParent.addView(nodeParent);
node.setNodeView(nodeParent);
mStack.push(node);
postInvalidate();
isScrolledLast = true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isScrolledLast) {
fullScroll(HorizontalScrollView.FOCUS_RIGHT);
isScrolledLast = false;
}
}
private void popNode(Node node) {
llParent.removeView(node.nodeView);
mStack.pop();
}
/**
* 拋出棧頂的數據
*/
public boolean popNode() {
if (mStack.size() == 1) {
return false;
}
Node node = mStack.pop();
llParent.removeView(node.nodeView);
if (dirNodeListener != null) {
dirNodeListener.onPopNode(mStack.peek().nodeId);
}
return true;
}
public static class Node {
private String nodeId;
private String nodeName;
private LinearLayout nodeView;
public Node(String nodeId, String nodeName) {
this.nodeId = nodeId;
this.nodeName = nodeName;
}
public String getNodeId() {
return nodeId;
}
public String getNodeName() {
return nodeName;
}
public LinearLayout getNodeView() {
return nodeView;
}
public void setNodeView(LinearLayout nodeView) {
this.nodeView = nodeView;
}
}
public interface DirNodeListener {
void onPopNode(String nodeId);
}
}