目录

  1. 引言 2
    1.1编写目的 2
    1.2项目背景 2
    1.3定义 3
  2. 总体设计 3
    2.1用例图 3
    2.2需求规定 4
    2.3全局变量 4
    2.4运行环境 4
    2.5开发工具 5
  3. UI设计 5
    3.1菜品推荐界面 5
    3.1.1界面简介 5
    3.1.2界面展示 5
    3.2菜品分类搜索 5
    3.2.1界面简介 5
    3.2.2界面展示 5
    3.2菜品详细信息展示界面 6
    3.2.1界面简介 6
    3.2.2界面展示 6
    3.3菜品评价界面 7
    3.3.1界面简介 7
    3.3.2界面展示 7
    3.4登录注册界面 7
    3.4.1界面简介 7
    3.4.2界面展示 7
    3.5用户中心界面 8
    3.5.1界面简介 8
    3.5.2界面展示 8
  4. 接口设计 9
    4.1接口列表 9
    4.2接口说明 13
  5. 项目总结 17
    1.引言
    为适应市场需求,满足顾客方便快捷的搜索到优秀餐饮,快速浏览菜品相关详细信息,本项目计划开发大众美食点评APP,该APP将会满足顾客的食品搜索,食品点评,店家搜索等需求。
    1.1编写目的
    本节描述软件详细设计文档的目的是:
    定义软件总体要求,作为用户和软件开发人员之间互相了解的基础;
    作为软件总体测试和系统结构设计的依据;
    本文档的预期读者包括:软件设计人员、模块开发人员、管理人员、测试人员。
    1.2项目背景
    项目名称:FoodFans;
    项目提出者:XXX;
    开发者:XXX,XXX,XXX;
    1.3定义
    MYSQL:一种免费的功能较强的数据库管理系统
    Android Studio:本文转载自http://www.biyezuopin.vip/onews.asp?id=14920基于IntelliJ IDEA. 类似Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试。
    1.4技术路线:retrofit+room+recyclerview+gridview+listview+livedata
    后端:springboot+mybatis+jwt(token验证)
    3.功能设计
    用户:
    注册、登录、找回密码、更改密码、修改个人信息
    浏览推荐菜谱文章(可含视频)或是通过分类后浏览菜谱文章(可含视频),
    对菜谱进行评论评分、点赞、收藏、分享和打赏
    发表相应菜谱文章(可含视频)
    搜素菜谱文章(可含视频)
    利用自己打赏的积分进行礼品兑换
    管理自己上传的菜谱文章(作品)
    查看自己的最近的浏览历史记录
    可以关注其他人
    关注之后可以发送留言消息
    查看自己的关注列表
    用户可以查看留言列表
    用户可以查看关注自己的粉丝列表

积分制度:
用途: 用来兑换系统提供的各种精美礼品
获得方式: 发表菜谱文章,积分充值,当某篇菜谱点赞数达到一定数量会为作者添加积分,当作者被人关注后也会添加积分。

package com.star.foodfans.ui.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;


import androidx.viewpager.widget.ViewPager;

import com.star.foodfans.R;

import java.util.List;


/**
 * ViewPagerIndicator
 * Created by HaPBoy on 5/10/16.
 */
public class ViewPagerIndicator extends HorizontalScrollView {

    private Context mContext;

    private List<String> mTitles; // 接收传递过来的title
    private ViewPager mViewPager; // 接收关联的ViewPager

    private LinearLayout llTabRoot; // Tab布局
    private RelativeLayout rlRoot; // 根布局
    private View vLine; // 横线
    private RelativeLayout.LayoutParams lineLayoutParams;

    private int mTabVisibleCount; // 可见tab的数量
    private int mSizeText; // tab标签文字大小(sp)
    private int mColorTextNormal; // 正常字体颜色
    private int mColorTextHighlight; // 高亮字体颜色
    private int mColorLine; // 横线颜色
    private int mHeightLine; // 线高(dp)

    private static final int COUNT_DEFAULT_TAB = 4; // 默认可见tab为4个
    private static final int SIZE_TEXT = 16; // 默认tab标签文字大小(sp)
    private static final int COLOR_TEXT_NORMAL = Color.parseColor("#000000"); // 默认正常字体颜色
    private static final int COLOR_TEXT_HIGHLIGHT = Color.parseColor("#FFFFFF"); // 默认高亮字体颜色
    private static final int COLOR_LINE = Color.parseColor("#000000"); // 默认横线颜色
    private static final int HEIGHT_LINE = 2; // 默认线高(dp)

    public ViewPagerIndicator(Context context) {
        super(context, null);
    }

    public ViewPagerIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;

        // 获取XML中的配置属性
        TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
        mTabVisibleCount = attributes.getInt(R.styleable.ViewPagerIndicator_tab_visible_count, COUNT_DEFAULT_TAB);
        if (mTabVisibleCount < 0) {
            mTabVisibleCount = COUNT_DEFAULT_TAB;
        }
        mSizeText = attributes.getInt(R.styleable.ViewPagerIndicator_tab_text_size, SIZE_TEXT);
        mColorTextNormal = attributes.getInt(R.styleable.ViewPagerIndicator_tab_text_normal_color, COLOR_TEXT_NORMAL);
        mColorTextHighlight = attributes.getInt(R.styleable.ViewPagerIndicator_tab_text_highlight_color, COLOR_TEXT_HIGHLIGHT);
        mColorLine = attributes.getInt(R.styleable.ViewPagerIndicator_tab_line_color, COLOR_LINE);
        mHeightLine = attributes.getInt(R.styleable.ViewPagerIndicator_tab_line_height, HEIGHT_LINE);
        attributes.recycle();

        initViews();
    }

    private void initViews() {
        setHorizontalScrollBarEnabled(false);

        // 根布局
        rlRoot = new RelativeLayout(mContext);
        rlRoot.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        this.addView(rlRoot);

        // Tab布局
        llTabRoot = new LinearLayout(mContext);
        llTabRoot.setOrientation(LinearLayout.HORIZONTAL);
        llTabRoot.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        rlRoot.addView(llTabRoot);

        // 横线
        vLine = new View(mContext);
        lineLayoutParams = new RelativeLayout.LayoutParams(getScreenWidth() / mTabVisibleCount, DpToPx(mHeightLine));
        lineLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        vLine.setLayoutParams(lineLayoutParams);
        vLine.setBackgroundColor(mColorLine);
        rlRoot.addView(vLine);
    }

    /**
     * xml加载完成之后,回调此方法
     * 设置每个tab的LayoutParams
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        int childCount = llTabRoot.getChildCount();
        if (childCount == 0) {
            return;
        }

        for (int i = 0; i < childCount; i++) {
            View view = llTabRoot.getChildAt(i);
            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
            params.width = getScreenWidth() / mTabVisibleCount;
            view.setLayoutParams(params);
        }

        // 横线长度
        lineLayoutParams.width = getScreenWidth() / mTabVisibleCount;
        vLine.setLayoutParams(lineLayoutParams);
    }

    /**
     * 动态设置tab的数量
     *
     * @param count
     */
    public void setVisibleTabCount(int count) {
        mTabVisibleCount = count;
        onFinishInflate();
    }

    /**
     * 动态设置tab
     *
     * @param titles
     */
    public void setTabItemTitles(List<String> titles) {
        if (titles != null && titles.size() > 0) {
            llTabRoot.removeAllViews();
            mTitles = titles;
            for (String title : mTitles) {
                llTabRoot.addView(generateTextView(title));
            }
            setItemClickEvent();
        }
    }

    /**
     * 根据title创建tab
     *
     * @param title
     * @return view
     */
    private View generateTextView(String title) {
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getScreenWidth() / mTabVisibleCount, LayoutParams.MATCH_PARENT);

        TextView textView = new TextView(getContext());
        textView.setText(title);
        textView.setGravity(Gravity.CENTER);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mSizeText);
        textView.setTextColor(mColorTextNormal);
        textView.setLayoutParams(params);
        return textView;
    }


    /**
     * 跟随ViewPager移动
     *
     * @param position
     * @param positionOffset
     */
    public void scroll(int position, float positionOffset) {
        int tabWidth = getWidth() / mTabVisibleCount;
        // 当Tab处于移动至最后一个时
        // position + 1 - (mTabVisibleCount - 1) + positionOffset
        if (position >= (mTabVisibleCount - 2) && positionOffset > 0 && llTabRoot.getChildCount() > mTabVisibleCount) {
            if (mTabVisibleCount != 1) {
                scrollTo((int) ((position - (mTabVisibleCount - 2) + positionOffset) * tabWidth), 0);
            } else {
                scrollTo((int) ((position + positionOffset) * tabWidth), 0);
            }
        }

        // 移动横线
        lineLayoutParams.leftMargin = (int) ((position + positionOffset) * tabWidth);
        vLine.setLayoutParams(lineLayoutParams);
    }

    /**
     * 设置关联的ViewPager
     *
     * @param viewpager
     * @param position
     */
    public void setViewPager(ViewPager viewpager, int position) {
        mViewPager = viewpager;
        mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

            @Override
            public void onPageSelected(int position) {
                highLightTextView(position);
            }

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                // 滑动Tab和横线
                scroll(position, positionOffset);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        mViewPager.setCurrentItem(position);
        highLightTextView(position);
    }

    /**
     * 高亮被点击的tab
     *
     * @param position
     */
    private void highLightTextView(int position) {
        resetTextViewColor();
        View view = llTabRoot.getChildAt(position);
        if (view instanceof TextView) {
            ((TextView) view).setTextColor(mColorTextHighlight);
        }
    }

    /**
     * 重置tab文本颜色
     */
    private void resetTextViewColor() {
        for (int i = 0; i < llTabRoot.getChildCount(); i++) {
            View view = llTabRoot.getChildAt(i);
            if (view instanceof TextView) {
                ((TextView) view).setTextColor(mColorTextNormal);
            }
        }
    }

    /**
     * 设置Tab的点击事件
     */
    private void setItemClickEvent() {
        int childCount = llTabRoot.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final int j = i;
            View view = llTabRoot.getChildAt(i);
            view.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    mViewPager.setCurrentItem(j);
                }
            });
        }
    }

    /**
     * 获取屏幕的宽度
     *
     * @return screenWidth
     */
    private int getScreenWidth() {
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return outMetrics.widthPixels;
    }

    /**
     * 将DP转换为PX
     *
     * @param dp 要转换的像素无关单位
     * @return int
     */
    private int DpToPx(double dp) {
        float scale = getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }
}

大众点评功能架构图 大众点评app界面设计分析_大众点评功能架构图


大众点评功能架构图 大众点评app界面设计分析_大众点评功能架构图_02


大众点评功能架构图 大众点评app界面设计分析_美食APP_03


大众点评功能架构图 大众点评app界面设计分析_java_04


大众点评功能架构图 大众点评app界面设计分析_java_05


大众点评功能架构图 大众点评app界面设计分析_java_06


大众点评功能架构图 大众点评app界面设计分析_美食点评APP_07


大众点评功能架构图 大众点评app界面设计分析_美食点评APP_08


大众点评功能架构图 大众点评app界面设计分析_大众点评功能架构图_09


大众点评功能架构图 大众点评app界面设计分析_大众点评功能架构图_10


大众点评功能架构图 大众点评app界面设计分析_大众点评功能架构图_11


大众点评功能架构图 大众点评app界面设计分析_大众点评功能架构图_12


大众点评功能架构图 大众点评app界面设计分析_大众点评功能架构图_13


大众点评功能架构图 大众点评app界面设计分析_java_14


大众点评功能架构图 大众点评app界面设计分析_大众点评功能架构图_15