1. 程式人生 > >android仿支付寶首頁更多、應用編輯介面

android仿支付寶首頁更多、應用編輯介面

[github地址](https://github.com/oldbirdy/recyclerdemo “github地址”) 專案越來越大,模組越來越多,首頁上展示的東西又不能全部都展示出來,只能選擇幾個重要的模組展示出來。但是不同的使用者關注的層面不一樣,只好讓使用者自己去選擇需要展示的應用。就像支付寶的應用編輯介面一樣。 我的介面效果圖 支付寶介面

整體介紹

總的來說實現了從json資料轉化為當前介面,可以自由的編輯介面儲存到本地。

主要介面佈局 一個標題欄,下面是一個RecyclerView(主要是拖拽實現很方便)。中間放了一個水平的HorizontalScrollView。下面是一個存放所有列表的RecyclerView

<?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" android:background="@drawable/bg_white" android:orientation="vertical">
<RelativeLayout android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="48dp" android:background="@drawable/bg_blue"
>
<TextView android:id="@+id/titletext" android:textSize="20sp" android:textColor="@color/white" android:layout_width="wrap_content" android:text="編輯我的應用" android:gravity="center_vertical" android:layout_height
="wrap_content" android:layout_centerInParent="true" />
<TextView android:id="@+id/submit" android:textSize="20sp" android:textColor="@color/white" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerInParent="true" android:gravity="center_vertical" android:text="儲存"/> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:padding="10dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我的應用" android:textColor="#333333" android:textSize="16sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:text="(按住可拖動調整順序)" android:textColor="#808080" android:textSize="13sp" /> </LinearLayout> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerViewExist" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingRight="10dp" /> <View android:layout_width="match_parent" android:layout_height="4dp" android:background="@color/line_color"> </View> <HorizontalScrollView android:id="@+id/horizonLScrollView" android:layout_width="match_parent" android:layout_height="35dp" android:scrollbarThumbHorizontal="@color/transparent" android:scrollbars="none"> <RadioGroup android:id="@+id/rg_tab" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="horizontal" /> </HorizontalScrollView> <View android:layout_width="match_parent" android:layout_height="1px" android:background="@color/line_color"> </View> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerViewAll" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingRight="10dp" /> </LinearLayout>

兩個實體類 tabItem(記錄每個tab項) 和FunctionItem(記錄每個功能模組)

public class TabItem {
    private String tabName="";
    private ArrayList<FunctionItem> functionItems;
    }
public class FunctionItem {
    public String name;
    public boolean isSelect = false;
    public String imageUrl = "";
    public String background ="";
    }

為了方便,通過GSON實現了測試資料。在庫檔案中。可以去生成測試資料。寫入到檔案中。

  ArrayList<TabItem> tabItems = new ArrayList<>();
        ArrayList<FunctionItem> arrayList = new ArrayList<>();
        arrayList.add(new FunctionItem("充值中心",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("信用卡還款",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("生活繳費",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("城市服務",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("生活號",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("我的客服",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("我的快遞",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("醫療健康",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("記賬本",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("城市一卡通",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("發票管家",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("螞蟻寶卡",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("車主服務",false,"icon_home_selected","#86c751"));
        arrayList.add(new FunctionItem("天天有料",false,"icon_home_selected","#86c751"));
        TabItem tabItem = new TabItem("便民生活",arrayList);
        tabItems.add(tabItem);

        ArrayList<FunctionItem> arrayList1 = new ArrayList<>();
        arrayList1.add(new FunctionItem("餘額寶",false,"icon_home_selected","#86c751"));
        arrayList1.add(new FunctionItem("花唄",false,"icon_home_selected","#86c751"));
        arrayList1.add(new FunctionItem("芝麻信用",false,"icon_home_selected","#86c751"));
        arrayList1.add(new FunctionItem("螞蟻借唄",false,"icon_home_selected","#86c751"));
        arrayList1.add(new FunctionItem("股票",false,"icon_home_selected","#86c751"));
        arrayList1.add(new FunctionItem("保險服務",false,"icon_home_selected","#86c751"));
        arrayList1.add(new FunctionItem("匯率換算",false,"icon_home_selected","#86c751"));
        arrayList1.add(new FunctionItem("理財小工具",false,"icon_home_selected","#86c751"));

        TabItem tabItem1 = new TabItem("財務管理",arrayList1);
        tabItems.add(tabItem1);

        ArrayList<FunctionItem> arrayList2 = new ArrayList<>();
        arrayList2.add(new FunctionItem("轉賬",false,"icon_home_selected","#86c751"));
        arrayList2.add(new FunctionItem("紅包",false,"icon_home_selected","#86c751"));
        arrayList2.add(new FunctionItem("AA收款",false,"icon_home_selected","#86c751"));
        arrayList2.add(new FunctionItem("親密付",false,"icon_home_selected","#86c751"));
        arrayList2.add(new FunctionItem("上銀匯款",false,"icon_home_selected","#86c751"));
        arrayList2.add(new FunctionItem("話費卡轉讓",false,"icon_home_selected","#86c751"));
        TabItem tabItem2 = new TabItem("資金往來",arrayList2);
        tabItems.add(tabItem2);

        ArrayList<FunctionItem> arrayList3 = new ArrayList<>();
        arrayList3.add(new FunctionItem("遊戲中心",false,"icon_home_selected","#86c751"));
        arrayList3.add(new FunctionItem("出境",false,"icon_home_selected","#86c751"));
        arrayList3.add(new FunctionItem("彩票",false,"icon_home_selected","#86c751"));
        arrayList3.add(new FunctionItem("人臉識別",false,"icon_home_selected","#86c751"));
        arrayList3.add(new FunctionItem("獎勵金",false,"icon_home_selected","#86c751"));
        arrayList3.add(new FunctionItem("世界盃",false,"icon_home_selected","#86c751"));
        TabItem tabItem3 = new TabItem("購物娛樂",arrayList3);
        tabItems.add(tabItem3);

        ArrayList<FunctionItem> arrayList4 = new ArrayList<>();
        arrayList4.add(new FunctionItem("大學生活",false,"icon_home_selected","#86c751"));
        arrayList4.add(new FunctionItem("愛心捐贈",false,"icon_home_selected","#86c751"));
        arrayList4.add(new FunctionItem("螞蟻森林",false,"icon_home_selected","#86c751"));
        arrayList4.add(new FunctionItem("螞蟻莊園",false,"icon_home_selected","#86c751"));
        arrayList4.add(new FunctionItem("中小學",false,"icon_home_selected","#86c751"));
        arrayList4.add(new FunctionItem("運動",false,"icon_home_selected","#86c751"));
        TabItem tabItem4 = new TabItem("教育公益",arrayList4);
        tabItems.add(tabItem4);

        ArrayList<FunctionItem> arrayList5 = new ArrayList<>();
        arrayList5.add(new FunctionItem("淘票票",false,"icon_home_selected","#86c751"));
        arrayList5.add(new FunctionItem("滴滴出行",false,"icon_home_selected","#86c751"));
        arrayList5.add(new FunctionItem("餓了麼外賣",false,"icon_home_selected","#86c751"));
        arrayList5.add(new FunctionItem("天貓",false,"icon_home_selected","#86c751"));
        arrayList5.add(new FunctionItem("淘寶",false,"icon_home_selected","#86c751"));
        arrayList5.add(new FunctionItem("火車票機票",false,"icon_home_selected","#86c751"));
        TabItem tabItem5 = new TabItem("第三方服務",arrayList5);
        tabItems.add(tabItem5);

        Gson gson = new Gson();
        String json = gson.toJson(tabItems);
        try {
            FileOutputStream fos = new FileOutputStream("ceshi.xml");
            fos.write(json.getBytes());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

有了測試資料之後,我將檔案複製到了Assert目錄下面。用來模擬資料請求。一般來說資料應該儲存在伺服器上。根據伺服器上請求的資料。去生成頁面。
第一個RecyclerView recyclerViewExist

 recyclerViewExist.setLayoutManager(new GridLayoutManager(this, 4));
        recyclerViewExist.setAdapter(blockAdapter);
        recyclerViewExist.addItemDecoration(new SpaceItemDecoration(4, dip2px(this, 10)));

        DefaultItemCallback callback = new DefaultItemCallback(blockAdapter);
        DefaultItemTouchHelper helper = new DefaultItemTouchHelper(callback);
        helper.attachToRecyclerView(recyclerViewExist);

blockAdapter主要是渲染一個item中圖片和文字,繫結點選的時候事件

@Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(inflater.inflate(R.layout.layout_grid_item, parent, false));
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        final int index = position;
        FunctionItem fi = data.get(position);
        setImage(fi.imageUrl, holder.iv);
        holder.text.setText(fi.name);
        holder.btn.setImageResource(R.drawable.ic_block_delete);
        holder.btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FunctionItem fi = data.remove(index);
                if (listener != null) {
                    listener.remove(fi);
                }
                notifyDataSetChanged();
            }
        });
    }

通過DefaultItemCallback和DefaultItemTouchHelper實現了拖拽。核心程式碼

  public DefaultItemCallback(ItemTouchHelperAdapter touchHelperAdapter) {
        this.touchHelperAdapter = touchHelperAdapter;
    }
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; //允許上下左右的拖動
        return makeMovementFlags(dragFlags, 0);
    }

recyclerViewAll下面的所有的內容。也只是提供了一個點選的回撥和佈局渲染。

 functionAdapter = new FunctionAdapter(this, allData);
        recyclerViewAll.setLayoutManager(gridManager);
        recyclerViewAll.setAdapter(functionAdapter);
        SpaceItemDecoration spaceDecoration = new SpaceItemDecoration(4, dip2px(this, 10));
        recyclerViewAll.addItemDecoration(spaceDecoration);

看一下中間horizonLScrollView 裡面寫了Radiogroup

向radiogoup新增radio.每次點選觸發一下回調函式

 for (int i = 0; i < size; i++) {
                    FunctionItem item = tabs.get(i);
                    if(item.isTitle){
                        scrollTab.add(item.name);
                        RadioButton rb = new RadioButton(this);
                        rb.setPadding(padding, 0, padding, 0);
                        rb.setButtonDrawable(null);
                        rb.setGravity(Gravity.CENTER);
                        rb.setText(item.name);
                        rb.setTag(i);
                        rb.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
                        try {
                            rb.setTextColor(getResources().getColorStateList(R.color.bg_block_text));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        rb.setCompoundDrawablesWithIntrinsicBounds(null, null, null, getResources().getDrawable(R.drawable.bg_block_tab));
                        rb.setOnCheckedChangeListener(onCheckedChangeListener);
                        rg_tab.addView(rb);
                    }
                }

當點選button的時候。根據上面rb.setTag(i)。這裡的i。表示選中的元素是所有列表的第幾個。每次點選的時候,呼叫下面的方法。移動到指定的位置

            private void moveToPosition(int position) {
        int first = gridManager.findFirstVisibleItemPosition();
        int end = gridManager.findLastVisibleItemPosition();
        if (first == -1 || end == -1)
            return;
        if (position <= first) {      //移動到前面
            gridManager.scrollToPosition(position);
        } else if (position >= end) {      //移動到後面
            isMove = true;
            scrollPosition = position;
            gridManager.smoothScrollToPosition(recyclerViewAll, null, position);
        } else {//中間部分
            int n = position - gridManager.findFirstVisibleItemPosition();
            if (n > 0 && n < allData.size()) {
                int top = gridManager.findViewByPosition(position).getTop();
                recyclerViewAll.scrollBy(0, top);
            }
        }
    }

當RecyclerView滑動的時候。更新一下HorizontalScrollView重的RadioGroup。

recyclerViewAll.addOnScrollListener(onScrollListener);  //新增一個滾動監聽

 private RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            try {
                if (isMove && newState == RecyclerView.SCROLL_STATE_IDLE) {
                    isMove = false;
                    View view = gridManager.findViewByPosition(scrollPosition);
                    if (view != null) {
                        int top = (int) view.getTop();
                        recyclerView.scrollBy(0, top);
                    }
                }
                if(newState==RecyclerView.SCROLL_STATE_DRAGGING){
                    isDrag = true;
                }else{
                    isDrag = false;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            if(isDrag){  //拖動過程中
                int position = gridManager.findFirstVisibleItemPosition();
                if(position>0){
                    for(int i=0;i<position+1;i++){
                        if(allData.get(i).isTitle){
                            currentTab = allData.get(i).name;
                        }
                    }
                    scrollTab(currentTab);
                }
            }
        }
    };



    private void scrollTab(String newTab) {
        try {
            int position = scrollTab.indexOf(currentTab);
            int targetPosition = scrollTab.indexOf(newTab);
            currentTab = newTab;
            if (targetPosition != -1) {
                int x = (targetPosition - position) * getTabWidth();
                RadioButton radioButton = ((RadioButton) rg_tab.getChildAt(targetPosition));
                radioButton.setOnCheckedChangeListener(null);
                radioButton.setChecked(true);
                radioButton.setOnCheckedChangeListener(onCheckedChangeListener);
                horizonLScrollView.scrollBy(x, 0);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

至此所有的核心程式碼都在這裡了。其中整個工程分為兩個部分。一個app的activity的module。另一個是ceshi的lib。其中ceshi的lib只是用來生成對應的。