Android项目实战系列—基于博学谷(七)课程模块(中)

Stella981
• 阅读 616

Android项目实战系列—基于博学谷(七)课程模块(中)

由于这个模块内容较多,分为上、中、下 三篇博客分别来讲述,请耐心阅读。


课程模块分为四个部分

  • [ ] 课程列表
  • [x] 课程详情
  • [ ] 视频播放
  • [ ] 播放记录

课程模块(中)主要讲述课程详情部分

一、课程详情界面

1、创建课程详情界面

com.boxuegu.activity包中创建一个Java类命名为VideoListActivity。在res/layout文件夹下创建一个布局文件,命名为activity_video_list

2、导入界面图片 default_video_list_icon.pngvodeo_list_intro_icon.png

3、界面代码——activity_video_list.xml

<?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="@android:color/white"
    android:orientation="vertical">
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="200dp"
        android:background="@drawable/default_video_list_icon"/>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:orientation="horizontal">
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:background="@drawable/video_list_intro_icon">
            <TextView
                android:layout_width="fill_parent"
                android:layout_height="46dp"
                android:id="@+id/tv_intro"
                android:layout_centerVertical="true"
                android:background="#30B4FF"
                android:gravity="center"
                android:text="简 介"
                android:textColor="#FFFFFF"
                android:textSize="20sp"/>
        </RelativeLayout>
        <View
            android:layout_width="1dp"
            android:layout_height="48dp"
            android:background="#C3C3C3"/>
        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="1"
            android:background="@drawable/video_list_intro_icon">
            <TextView
                android:layout_width="fill_parent"
                android:layout_height="46dp"
                android:id="@+id/tv_video"
                android:layout_centerVertical="true"
                android:background="#FFFFFF"
                android:gravity="center"
                android:text="视 频"
                android:textColor="#000000"
                android:textSize="20sp"/>
        </RelativeLayout>
    </LinearLayout>
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <ListView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/lv_video_list"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:divider="#E4E4E4"
            android:dividerHeight="1dp"
            android:scrollbars="none"
            android:visibility="gone"/>
        <ScrollView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/sv_chapter_intro">
            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="horizontal">
                <TextView
                    android:layout_width="fill_parent"
                    android:layout_height="fill_parent"
                    android:id="@+id/tv_chapter_intro"
                    android:lineSpacingMultiplier="1.5"
                    android:padding="10dp"
                    android:text="wordpress简介"
                    android:textColor="@android:color/black"
                    android:textSize="14sp"/>
            </LinearLayout>
        </ScrollView>
    </RelativeLayout>

</LinearLayout>

二、课程详情界面Item

1、创建课程详情界面item

res/layout文件夹下创建一个布局文件,命名为video_list_item。导入所需图片 course_bar_icon.png

2、界面代码——video_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/white"
    android:gravity="center_vertical"
    android:paddingBottom="15dp"
    android:paddingTop="15dp">
    <ImageView
        android:id="@+id/iv_left_icon"
        android:layout_width="25dp"
        android:layout_height="25dp"
        android:src="@drawable/course_bar_icon" />
    <TextView
        android:id="@+id/tv_video_title"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_marginLeft="10dp"
        android:gravity="center_vertical"
        android:textColor="#333333"
        android:textSize="14sp"/>
</LinearLayout>

三、创建VideoBean

com.boxuegu.bean包中创建一个VideoBean类,用来创建视频的所有属性。
package com.boxuegu.bean;

public class VideoBean {
    public int chapterId;       //章节ID
    public int videoId;            //视频ID
    public String title;        //章节标题
    public String secondTitle;    //视频标题
    public String videoPath;    //视频播放地址
}

四、课程界面Adapter

com.boxuegu.adapter包中创建一个VideoListAdapter类。代码如下:
package com.boxuegu.adapter;

import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import com.boxuegu.R;
import com.boxuegu.bean.VideoBean;

//列表
public class VideoListAdapter extends BaseAdapter{

    private Context mContext;
    private List<VideoBean> vbl;  //视频列表数据
    private int selectedPosition = -1;  //点击时选中的位置
    private OnSelectListener onSelectListener;
    public VideoListAdapter(Context context,OnSelectListener onSelectListener){
        this.mContext = context;
        this.onSelectListener = onSelectListener;
    }

    public void setSelectedPosition(int position){
        selectedPosition = position;
    }

    //设置数据更新界面
    public void setData(List<VideoBean> vbl){
        this.vbl = vbl;
        notifyDataSetChanged();
    }

    //获取Item的总数
    @Override
    public int getCount() {
        return vbl == null ? 0 : vbl.size();
    }

  //根据position得到item对应的对象
    @Override
    public VideoBean getItem(int position) {
        return vbl == null ? null : vbl.get(position);
    }

    //根据position得到item对应的ID
    @Override
    public long getItemId(int position) {
        return position;
    }

    //得到对应position的item视图
    @Override
    public View getView(final int position, View view, ViewGroup viewGroup) {
        final ViewHolder vh;
        if (view == null){
            vh = new ViewHolder();
            view = LayoutInflater.from(mContext).inflate(
                    R.layout.video_list_item,null
            );
            vh.tv_title = (TextView) view.findViewById(R.id.tv_video_title);
            vh.iv_icon = (ImageView) view.findViewById(R.id.iv_left_icon);
            view.setTag(vh);
        }else {
            vh = (ViewHolder) view.getTag();
        }
        final VideoBean bean = getItem(position);
        vh.iv_icon.setImageResource(R.drawable.course_bar_icon);
        vh.tv_title.setTextColor(Color.parseColor("#333333"));
        if (bean!=null){
            vh.tv_title.setText(bean.secondTitle);
            //设置选中效果
            if (selectedPosition == position){
                vh.iv_icon.setImageResource(R.drawable.course_intro_icon);
                vh.tv_title.setTextColor(Color.parseColor("#009958"));

            }else {
                vh.iv_icon.setImageResource(R.drawable.course_bar_icon);
                vh.tv_title.setTextColor(Color.parseColor("#333333"));
            }
        }
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (bean == null)
                    return;
                //播放视频
                onSelectListener.onSelect(position,vh.iv_icon);
            }
        });
        return view;
    }

    class ViewHolder{
        public TextView tv_title;
        public ImageView iv_icon;
    }

    //创建接口,传递position和ImageView
    public interface OnSelectListener{
        void onSelect(int position,ImageView iv);
    }
}

五、视频列表数据的存放

1、Eclipse新建json文件,并改变文件的编码。

assets文件夹中右键,选择new,点击file

Android项目实战系列—基于博学谷(七)课程模块(中)

文件名输入data.json

Android项目实战系列—基于博学谷(七)课程模块(中)

由于默认的编码会导致软件运行以后中文出现乱码。在data.json文件里面,使用Alt+Enter快捷键弹出修改编码的对话框,编码方式选择UTF-8即可。

Android项目实战系列—基于博学谷(七)课程模块(中)

2、data.json代码如下:

[
 {
  "chapterId": 1,
  "videoId": "1",
  "title": "第1章 博客(网站)简介",
  "secondTitle": "什么是博客",
  "videoPath": "video11.mp4"
 },
 {
  "chapterId": 1,
  "videoId": "2",
  "title": "第1章 博客(网站)简介",
  "secondTitle": "网站与博客的关系",
  "videoPath": "beyond.mp4"
 },
 {
  "chapterId": 2,
  "videoId": "1",
  "title": "第2章 Linux系统简介",
  "secondTitle": "认识Linux",
  "videoPath": ""
 },
 {
  "chapterId": 2,
  "videoId": "2",
  "title": "第2章 Linux系统简介",
  "secondTitle": "CentOS 7简单操作",
  "videoPath": ""
 },
 {
  "chapterId": 3,
  "videoId": "1",
  "title": "第3章  WordPress简介",
  "secondTitle": "动态博客系统",
  "videoPath": ""
 },
 {
  "chapterId": 3,
  "videoId": "2",
  "title": "第3章 WordPress简介",
  "secondTitle": "WordPress系统",
  "videoPath": ""
 },
 {
  "chapterId": 4,
  "videoId": "1",
  "title": "第4章 安装MySQL数据库",
  "secondTitle": "MySQL数据库简介",
  "videoPath": ""
 },
 {
  "chapterId": 4,
  "videoId": "2",
  "title": "第4章 安装MySQL数据库",
  "secondTitle": "安装MySQL数据库",
  "videoPath": ""
 },
 {
  "chapterId": 5,
  "videoId": "1",
  "title": "第5章 数据存储服务器",
  "secondTitle": "常见的服务器",
  "videoPath": ""
 },
 {
  "chapterId": 5,
  "videoId": "2",
  "title": "第5章 数据存储服务器",
  "secondTitle": "Nginx的安装",
  "videoPath": ""
 },
 {
  "chapterId": 6,
  "videoId": "1",
  "title": "第6章 安装PHP环境",
  "secondTitle": "PHP语法简介",
  "videoPath": ""
 },
 {
  "chapterId": 6,
  "videoId": "2",
  "title": "第6章 安装PHP环境",
  "secondTitle": "安装PHP",
  "videoPath": ""
 },
 {
  "chapterId": 7,
  "videoId": "1",
  "title": "第7章 云服务器的购买",
  "secondTitle": "购买云服务器",
  "videoPath": ""
 },
 {
  "chapterId": 7,
  "videoId": "2",
  "title": "第7章 云服务器的购买",
  "secondTitle": "云服务器的简单配置",
  "videoPath": ""
 },
 {
  "chapterId": 8,
  "videoId": "1",
  "title": "第8章 域名购买及备案",
  "secondTitle": "购买域名",
  "videoPath": ""
 },
 {
  "chapterId": 8,
  "videoId": "2",
  "title": "第8章 域名购买及备案",
  "secondTitle": "域名备案",
  "videoPath": ""
 },
 {
  "chapterId": 9,
  "videoId": "1",
  "title": "第9章 安装WordPress",
  "secondTitle": "安装前准备",
  "videoPath": ""
 },
 {
  "chapterId": 9,
  "videoId": "2",
  "title": "第9章 安装WordPress",
  "secondTitle": "安装WordPress",
  "videoPath": ""
 },
 {
  "chapterId": 10,
  "videoId": "1",
  "title": "第10章 WordPress简单设置",
  "secondTitle": "更换博客主题",
  "videoPath": ""
 },
 {
  "chapterId": 10,
  "videoId": "2",
  "title": "第10章 WordPress简单设置",
  "secondTitle": "博客基本布局设置",
  "videoPath": ""
 }
]

六、课程详情界面逻辑代码

1、界面代码——VideoListActivity.java

package com.boxuegu.activity;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import com.boxuegu.R;
import com.boxuegu.adapter.VideoListAdapter;
import com.boxuegu.bean.VideoBean;
import com.boxuegu.utils.AnalysisUtils;
import com.boxuegu.utils.DBUtils;

public class VideoListActivity extends AppCompatActivity implements View.OnClickListener {

    private String intro;
    private int chapterId;
    private DBUtils db;
    private ArrayList<VideoBean> videoList;
    private TextView tv_intro;
    private TextView tv_video;
    private ListView lv_video_list;
    private TextView tv_chapter_intro;
    private ScrollView sv_chapter_intro;
    private VideoListAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_list);
        //设置界面为视频
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        //从课程界面传过来的章节ID
        chapterId = getIntent().getIntExtra("id", 0);
        //从课程界面传过来的章节简介
        intro = getIntent().getStringExtra("intro");
        db = DBUtils.getInstance(VideoListActivity.this);
        initData();
        initView();

    }

    //初始化界面UI控件
    private void initView() {
        tv_intro = (TextView) findViewById(R.id.tv_intro);
        tv_video = (TextView) findViewById(R.id.tv_video);
        lv_video_list = (ListView) findViewById(R.id.lv_video_list);
        tv_chapter_intro = (TextView) findViewById(R.id.tv_chapter_intro);
        sv_chapter_intro = (ScrollView)findViewById(R.id.sv_chapter_intro);
        adapter = new VideoListAdapter(this, new VideoListAdapter.OnSelectListener() {
            @Override
            public void onSelect(int position, ImageView iv) {
                adapter.setSelectedPosition(position); //设置适配器的选中项
                VideoBean bean = videoList.get(position);
                String videoPath = bean.videoPath;
                //notifyDataSetChanged刷新UI
                adapter.notifyDataSetChanged();
                if (TextUtils.isEmpty(videoPath)){
                    Toast.makeText(VideoListActivity.this,"本地没有此视频,暂时无法播放",Toast.LENGTH_SHORT).show();
                    return;
                }else {
                    //判断用户是否登录,若登录则把视频添加到记录中
                    if (readLoginStatus()){
                        String userName = AnalysisUtils.readLoginUserName(VideoListActivity.this);
                        db.saveVideoPlayList(videoList.get(position),userName);

                    }
                    //跳转到视频播放界面

                }
            }
        });
        lv_video_list.setAdapter(adapter);
        tv_intro.setOnClickListener(this);
        tv_video.setOnClickListener(this);
        adapter.setData(videoList);
        tv_chapter_intro.setText(intro);
        tv_intro.setBackgroundColor(Color.parseColor("#30B4FF"));
        tv_video.setBackgroundColor(Color.parseColor("#FFFFFF"));
        tv_intro.setTextColor(Color.parseColor("#FFFFFF"));
        tv_video.setTextColor(Color.parseColor("#000000"));


    }
    /**
     * 设置视频列表本地数据
     */
    private void initData() {
        //多个视频,用jsonArray
        JSONArray jsonArray;
        InputStream is = null;
        try {
            is = getResources().getAssets().open("data.json");
            jsonArray = new JSONArray(read(is));
            videoList = new ArrayList<VideoBean>();
            for (int i = 0;i < jsonArray.length();i++){
                VideoBean bean = new VideoBean();
                JSONObject jsonObj = jsonArray.getJSONObject(i);
                if(jsonObj.getInt("chapterId") == chapterId){
                    bean.chapterId = jsonObj.getInt("chapterId");
                    bean.videoId = Integer.parseInt(jsonObj.getString("videoId"));
                    bean.title = jsonObj.getString("title");
                    bean.secondTitle = jsonObj.getString("secondTitle");
                    bean.videoPath = jsonObj.getString("videoPath");
                    videoList.add(bean);
                }
                bean = null;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
/*
    *读取数据流,参数in就是数据流,把输入流转换成字符串
     */

    private String read(InputStream in) {
        BufferedReader reader = null;
        StringBuilder sb = null;
        String line = null;
        try {
            sb = new StringBuilder(); //实例化一个StringBulider对象
            //InoutStreamReader把in字节流转换成字符流
            reader = new BufferedReader(new InputStreamReader(in));
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

    /**
     * 从SharedPreferences读取登录状态
     */

    private boolean readLoginStatus() {
        SharedPreferences sp = getSharedPreferences("loginInfo", Context.MODE_PRIVATE);
        boolean isLogin = sp.getBoolean("isLogin",false);
        return isLogin;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data!=null){
            //
            int position = data.getIntExtra("position",0);
            adapter.setSelectedPosition(position);
            //
            lv_video_list.setVisibility(View.VISIBLE);
            sv_chapter_intro.setVisibility(View.GONE);
            tv_intro.setBackgroundColor(Color.parseColor("#FFFFFF"));
            tv_video.setBackgroundColor(Color.parseColor("#30B4FF"));
            tv_intro.setTextColor(Color.parseColor("#000000"));
            tv_video.setTextColor(Color.parseColor("#FFFFFF"));

        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.tv_intro:  //简介
                lv_video_list.setVisibility(View.GONE);
                sv_chapter_intro.setVisibility(View.VISIBLE);
                tv_intro.setBackgroundColor(Color.parseColor("#30B4FF"));
                tv_video.setBackgroundColor(Color.parseColor("#FFFFFF"));
                tv_intro.setTextColor(Color.parseColor("#FFFFFF"));
                tv_video.setTextColor(Color.parseColor("#000000"));
                break; 
            case R.id.tv_video:  //视频
                lv_video_list.setVisibility(View.VISIBLE);
                sv_chapter_intro.setVisibility(View.GONE);
                tv_intro.setBackgroundColor(Color.parseColor("#FFFFFF"));
                tv_intro.setTextColor(Color.parseColor("#000000"));
                tv_video.setBackgroundColor(Color.parseColor("#30B4FF"));
                tv_video.setTextColor(Color.parseColor("#FFFFFF"));
                break;
            default:
                break;
        }
    }
}

2、修改代码

(1)、找到SQLiteHelper.java文件,在 public static final String U_USERINFO = "userinfo"; 下方添加如下代码:
public static final String U_VIDEO_PLAY_LIST = "videoplaylist";  //视频播放列表
(2)、找到SQLiteHelper.java文件,在onCreate()方法里面添加如下代码:
//创建视频播放记录
        db.execSQL("CREATE TABLE IF NOT EXISTS " + U_VIDEO_PLAY_LIST + "( " +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
                + "userName VARCHAR,"//用户名
                + "chapterId INT," //章节id
                + "videoId INT,"//小节id
                + "videoPath VARCHAR,"
                + "title VARCHAR,"  //章节名字
                + "secondTitle VARCHAR" // 视频名字
                + ")");
(3)、找到SQLiteHelper.java文件,在onUpgrade()方法里面的onCreate(db);语句前添加如下代码:
db.execSQL("DROP TABLE IF NOT EXISTS " + U_VIDEO_PLAY_LIST);
(4)、找到DBUtils.java文件,添加如下代码:
 //保存视频播放记录
    public void saveVideoPlayList(VideoBean bean, String userName) {
        //判断如果里面已经有此记录则需要先删除再重新存放
        if (hasVideoPlay(bean.chapterId, bean.videoId, userName)) {
            boolean isDelete = delVideoPlay(bean.chapterId, bean.videoId, userName);
            if (!isDelete) {
                //没有删除成功
                return;
            }
        }
        ContentValues cv = new ContentValues();
        cv.put("userName", userName);
        cv.put("chapterId", bean.chapterId);
        cv.put("videoId", bean.videoId);
        cv.put("videoPath", bean.videoPath);
        cv.put("title", bean.title);
        cv.put("secondTitle", bean.secondTitle);
        db.insert(SQLiteHelper.U_VIDEO_PLAY_LIST, null, cv);

    }

    /**
     * 删除已经存在的是视屏记录
     * @param chapterId
     * @param videoId
     * @param userName
     * @return
     */

    public boolean delVideoPlay(int chapterId, int videoId, String userName) {
        boolean delSuccess = false;
        int row = db.delete(SQLiteHelper.U_VIDEO_PLAY_LIST, " chapterId=? AND videoId=? AND userName=?",
                new String[]{chapterId + "", videoId + "", userName});
        if (row > 0) {
            delSuccess = true;
        }

        return delSuccess;
    }
    /**
     * 判断视频记录是否存在
     * @param chapterId
     * @param videoId
     * @param userName
     * @return
     */
    public boolean hasVideoPlay(int chapterId, int videoId, String userName) {
        boolean hasVideo = false;
        String sql = "SELECT * FROM " + SQLiteHelper.U_VIDEO_PLAY_LIST + " WHERE chapterId=? AND videoId=? AND userName =?";
        Cursor cursor = db.rawQuery(sql, new String[]{ chapterId + "", videoId + "", userName});
        if (cursor.moveToFirst()) {
            hasVideo = true;
        }
        cursor.close();
        return hasVideo;
    }
(5)、找到CourseAdapter.java文件,在两处注释//跳转到课程详情界面分别添加以下代码:
 Intent intent = new Intent(mContext, VideoListActivity.class);
intent.putExtra("id",bean.id);
intent.putExtra("intro",bean.intro);
mContext.startActivity(intent);

七、运行效果

Android项目实战系列—基于博学谷(七)课程模块(中)

Android项目实战系列—基于博学谷 开源地址

Android项目实战系列—基于博学谷(七)课程模块(中)                 Android项目实战系列—基于博学谷(七)课程模块(中)

点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(七)课程模块(下)
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)由于这个模块内容较多,分为上、中、下三篇博客分别来讲述,请耐心阅读。课程模块分为四个部分\\课程列表\\课
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(一)项目综述
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)一、项目分析1、项目名称WordPress建站APP2、项目概述WordPress建站是一个学习博客建站技术的APP
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(四)我的模块(上)
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)由于这个模块内容较多,篇幅较长,请耐心阅读。“我”的模块分为四个部分\x\我的界面\x\设置界面\
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(四)我的模块(下)
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)由于这个模块内容较多,篇幅较长,请耐心阅读。“我”的模块分为四个部分\\我的界面\\设置界面\x
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(三)注册与登录模块
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)由于这个模块内容较多,篇幅较长,请耐心阅读。注册与登录模块分为三个部分\x\欢迎界面\x\注册界面\
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(六)习题模块
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)由于这个模块内容较多,篇幅较长,请耐心阅读。习题模块分为两个部分\x\习题列表界面\x\习题详情界面
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(七)课程模块(上)
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)由于这个模块内容较多,分为上、中、下三篇博客分别来讲述,请耐心阅读。课程模块分为四个部分\x\课程列表\\课
Wesley13 Wesley13
3年前
C#实战系列—学生信息管理系统(三)项目打包
!image(https://www.cztcms.cn/wpcontent/uploads/2020/05/c特色图片.png)学生信息管理系统分为三个部分\\项目展示\
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(二)界面设计
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)一、原型设计介绍百度百科:原型设计是交互设计师与PD、PM、网站开发工程师沟通的最好工具。而该块的设计在原则上必须是交互设计师的产物,交互设
Stella981 Stella981
3年前
Android项目实战系列—基于博学谷(五)个人资料
!image(https://www.cztcms.cn/wpcontent/uploads/2020/03/%E5%8D%9A%E5%AD%A6%E8%B0%B7.png)由于这个模块内容较多,篇幅较长,请耐心阅读。个人资料模块分为两个部分\x\个人资料\x\资料修改