فهرست منبع

增加老师端我的课程页面-视频课逻辑

Pq 3 سال پیش
والد
کامیت
51d27ef205

+ 5 - 3
BaseLibrary/build.gradle

@@ -121,7 +121,9 @@ dependencies {
     api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.7'
     api 'com.contrarywind:Android-PickerView:4.1.9'
 
-    api  'io.github.scwang90:refresh-layout-kernel:2.0.5'      //核心必须依赖
-    api  'io.github.scwang90:refresh-header-classics:2.0.5'    //经典刷新头
-    api  'io.github.scwang90:refresh-footer-classics:2.0.5'    //经典加载
+    api 'io.github.scwang90:refresh-layout-kernel:2.0.5'      //核心必须依赖
+    api 'io.github.scwang90:refresh-header-classics:2.0.5'    //经典刷新头
+    api 'io.github.scwang90:refresh-footer-classics:2.0.5'    //经典加载
+
+    api "de.hdodenhof:circleimageview:2.2.0"
 }

+ 8 - 0
BaseLibrary/src/main/res/drawable/bg_white_bottom_10dp.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/white" />
+    <corners
+        android:bottomLeftRadius="10dp"
+        android:bottomRightRadius="10dp" />
+</shape>

+ 48 - 0
teacher/src/main/java/com/cooleshow/teacher/adapter/VideoCourseListAdapter.java

@@ -0,0 +1,48 @@
+package com.cooleshow.teacher.adapter;
+
+import android.widget.ImageView;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.module.BaseLoadMoreModule;
+import com.chad.library.adapter.base.module.LoadMoreModule;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+import com.cooleshow.base.utils.GlideUtils;
+import com.cooleshow.teacher.R;
+import com.cooleshow.teacher.bean.VideoCourseListBean;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Author by pq, Date on 2022/4/26.
+ */
+public class VideoCourseListAdapter extends BaseQuickAdapter<VideoCourseListBean.RowsBean, BaseViewHolder> implements LoadMoreModule {
+
+    public VideoCourseListAdapter(int layoutResId) {
+        super(layoutResId);
+    }
+
+    @Override
+    protected void convert(@NonNull BaseViewHolder holder, VideoCourseListBean.RowsBean data) {
+        ImageView iv_bg = holder.getView(R.id.iv_bg);
+        //封面
+        GlideUtils.INSTANCE.loadImage(getContext(), data.lessonCoverUrl, iv_bg);
+        //title
+        holder.setText(R.id.tv_title, data.lessonName);
+        //头像
+        ImageView cir_avatar = holder.getView(R.id.cir_avatar);
+        GlideUtils.INSTANCE.loadImage(getContext(), data.avatar, cir_avatar);
+        //老师名称
+        holder.setText(R.id.tv_author_name, data.username);
+        //购买人数
+        holder.setText(R.id.tv_buy_num, getContext().getString(R.string.pay_count_str, data.countStudent));
+        //¥120/4课时
+        String price = "¥" + data.lessonPrice + "/" + data.lessonCount + "课时";
+        holder.setText(R.id.tv_price, price);
+    }
+
+    @NonNull
+    @Override
+    public BaseLoadMoreModule addLoadMoreModule(@NonNull BaseQuickAdapter<?, ?> baseQuickAdapter) {
+        return new BaseLoadMoreModule(baseQuickAdapter);
+    }
+}

+ 12 - 1
teacher/src/main/java/com/cooleshow/teacher/api/APIService.java

@@ -4,6 +4,7 @@ import com.cooleshow.base.data.net.BaseResponse;
 import com.cooleshow.teacher.bean.CourseTableDataBean;
 import com.cooleshow.teacher.bean.LiveCourseListBean;
 import com.cooleshow.teacher.bean.SparringCourseListBean;
+import com.cooleshow.teacher.bean.VideoCourseListBean;
 
 import java.util.List;
 
@@ -49,7 +50,7 @@ public interface APIService {
 
 
     /**
-     * 查询陪练
+     * 查询直播
      *
      * @param
      * @return
@@ -57,6 +58,16 @@ public interface APIService {
     @POST(TEACHER_GROUP + "courseSchedule/queryTeacherLiveCourse")
     Observable<BaseResponse<LiveCourseListBean>> getLiveCourses(@Body RequestBody body);
 
+
+    /**
+     * 查询视频课
+     *
+     * @param
+     * @return
+     */
+    @POST(TEACHER_GROUP + "videoLessonGroup/page")
+    Observable<BaseResponse<VideoCourseListBean>> getVideoCourses(@Body RequestBody body);
+
     /**
      * 查询个人信息
      *

+ 132 - 0
teacher/src/main/java/com/cooleshow/teacher/bean/VideoCourseListBean.java

@@ -0,0 +1,132 @@
+package com.cooleshow.teacher.bean;
+
+import java.util.List;
+
+/**
+ * Author by pq, Date on 2022/4/25.
+ */
+public class VideoCourseListBean {
+
+    /**
+     * footer : [{"auditId":0,"auditName":"","auditStatus":"","avatar":"","countStudent":0,"createTime":"","hotFlag":0,"id":0,"lessonCount":0,"lessonCoverUrl":"","lessonDesc":"","lessonName":"","lessonPrice":0,"lessonSubject":"","lessonSubjectName":"","lessonTag":"","sortNumber":0,"teacherId":0,"topFlag":0,"updateTime":"","username":""}]
+     * limit : 0
+     * nextPage : 0
+     * offset : 0
+     * pageNo : 0
+     * prePage : 0
+     * rows : [{"auditId":0,"auditName":"","auditStatus":"","avatar":"","countStudent":0,"createTime":"","hotFlag":0,"id":0,"lessonCount":0,"lessonCoverUrl":"","lessonDesc":"","lessonName":"","lessonPrice":0,"lessonSubject":"","lessonSubjectName":"","lessonTag":"","sortNumber":0,"teacherId":0,"topFlag":0,"updateTime":"","username":""}]
+     * statInfo : {}
+     * total : 0
+     * totalPage : 0
+     */
+
+    public int limit;
+    public int nextPage;
+    public int offset;
+    public int pageNo;
+    public int prePage;
+    public StatInfoBean statInfo;
+    public int total;
+    public int totalPage;
+    public List<FooterBean> footer;
+    public List<RowsBean> rows;
+
+    public static class StatInfoBean {
+    }
+
+    public static class FooterBean {
+        /**
+         * auditId : 0
+         * auditName :
+         * auditStatus :
+         * avatar :
+         * countStudent : 0
+         * createTime :
+         * hotFlag : 0
+         * id : 0
+         * lessonCount : 0
+         * lessonCoverUrl :
+         * lessonDesc :
+         * lessonName :
+         * lessonPrice : 0
+         * lessonSubject :
+         * lessonSubjectName :
+         * lessonTag :
+         * sortNumber : 0
+         * teacherId : 0
+         * topFlag : 0
+         * updateTime :
+         * username :
+         */
+
+        public int auditId;
+        public String auditName;
+        public String auditStatus;
+        public String avatar;
+        public int countStudent;
+        public String createTime;
+        public int hotFlag;
+        public int id;
+        public int lessonCount;
+        public String lessonCoverUrl;
+        public String lessonDesc;
+        public String lessonName;
+        public int lessonPrice;
+        public String lessonSubject;
+        public String lessonSubjectName;
+        public String lessonTag;
+        public int sortNumber;
+        public int teacherId;
+        public int topFlag;
+        public String updateTime;
+        public String username;
+    }
+
+    public static class RowsBean {
+        /**
+         * auditId : 0
+         * auditName :
+         * auditStatus :
+         * avatar :
+         * countStudent : 0
+         * createTime :
+         * hotFlag : 0
+         * id : 0
+         * lessonCount : 0
+         * lessonCoverUrl :
+         * lessonDesc :
+         * lessonName :
+         * lessonPrice : 0
+         * lessonSubject :
+         * lessonSubjectName :
+         * lessonTag :
+         * sortNumber : 0
+         * teacherId : 0
+         * topFlag : 0
+         * updateTime :
+         * username :
+         */
+
+        public int auditId;
+        public String auditName;
+        public String auditStatus;
+        public String avatar;
+        public String countStudent;
+        public String createTime;
+        public int hotFlag;
+        public int id;
+        public int lessonCount;
+        public String lessonCoverUrl;
+        public String lessonDesc;
+        public String lessonName;
+        public int lessonPrice;
+        public String lessonSubject;
+        public String lessonSubjectName;
+        public String lessonTag;
+        public int sortNumber;
+        public int teacherId;
+        public int topFlag;
+        public String updateTime;
+        public String username;
+    }
+}

+ 21 - 0
teacher/src/main/java/com/cooleshow/teacher/contract/VideoCourseContract.java

@@ -0,0 +1,21 @@
+package com.cooleshow.teacher.contract;
+
+import com.cooleshow.base.presenter.view.BaseView;
+import com.cooleshow.teacher.bean.LiveCourseListBean;
+import com.cooleshow.teacher.bean.VideoCourseListBean;
+
+/**
+ * Author by pq, Date on 2022/4/20.
+ */
+public interface VideoCourseContract {
+
+    interface VideoCourseView extends BaseView {
+        void onGetVideoCourseSuccess(int page, VideoCourseListBean liveCourseListBean);
+
+        void onGetCourseError(int page);
+    }
+
+    interface Presenter {
+        void queryVideoCourse(int subjectId, int page);
+    }
+}

+ 53 - 0
teacher/src/main/java/com/cooleshow/teacher/presenter/course/VideoCoursePresenter.java

@@ -0,0 +1,53 @@
+package com.cooleshow.teacher.presenter.course;
+
+import com.cooleshow.base.presenter.BasePresenter;
+import com.cooleshow.base.rx.BaseObserver;
+import com.cooleshow.base.utils.RequestBodyUtil;
+import com.cooleshow.teacher.api.APIService;
+import com.cooleshow.teacher.bean.LiveCourseListBean;
+import com.cooleshow.teacher.bean.VideoCourseListBean;
+import com.cooleshow.teacher.contract.LiveCourseContract;
+import com.cooleshow.teacher.contract.VideoCourseContract;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * 陪练课presenter
+ * Author by pq, Date on 2022/4/20.
+ */
+public class VideoCoursePresenter extends BasePresenter<VideoCourseContract.VideoCourseView> implements VideoCourseContract.Presenter {
+
+    @Override
+    public void queryVideoCourse(int subjectId, int page) {
+        if (getView() != null) {
+            getView().showLoading();
+        }
+        JSONObject jsonObject = new JSONObject();
+        try {
+            if (subjectId != 0) {
+                jsonObject.putOpt("subjectId", subjectId);
+            }
+            jsonObject.putOpt("page", page);
+            jsonObject.putOpt("rows", 10);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+        addSubscribe(create(APIService.class).getVideoCourses(RequestBodyUtil.convertToRequestBodyJson(jsonObject.toString())), new BaseObserver<VideoCourseListBean>(getView()) {
+            @Override
+            protected void onSuccess(VideoCourseListBean data) {
+                if (getView() != null) {
+                    getView().onGetVideoCourseSuccess(page, data);
+                }
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                super.onError(e);
+                if (getView() != null) {
+                    getView().onGetCourseError(page);
+                }
+            }
+        });
+    }
+}

+ 1 - 1
teacher/src/main/java/com/cooleshow/teacher/ui/course/LiveCourseFragment.java

@@ -108,7 +108,7 @@ public class LiveCourseFragment extends BaseMVPFragment<FragmentLiveCourseLayout
         });
 
         mAdapter = new LiveCourseListAdapter(R.layout.item_live_course_list_layout);
-        mAdapter.getLoadMoreModule().setEnableLoadMoreIfNotFullPage(false);
+//        mAdapter.getLoadMoreModule().setEnableLoadMoreIfNotFullPage(false);
         mAdapter.getLoadMoreModule().setOnLoadMoreListener(new OnLoadMoreListener() {
             @Override
             public void onLoadMore() {

+ 2 - 2
teacher/src/main/java/com/cooleshow/teacher/ui/course/MineCourseActivity.java

@@ -88,11 +88,11 @@ public class MineCourseActivity extends BaseMVPActivity<ActivityMineCourseLayout
     public void initData() {
         super.initData();
         SparringCourseFragment sparringCourseFragment = new SparringCourseFragment();
-        SparringCourseFragment sparringCourseFragment2 = new SparringCourseFragment();
         LiveCourseFragment liveCourseFragment = new LiveCourseFragment();
+        VideoCourseFragment videoCourseFragment = new VideoCourseFragment();
         mFragments.add(sparringCourseFragment);
         mFragments.add(liveCourseFragment);
-        mFragments.add(sparringCourseFragment2);
+        mFragments.add(videoCourseFragment);
         MineCoursePageAdapter mineCoursePageAdapter = new MineCoursePageAdapter(this);
         mineCoursePageAdapter.setFragments(mFragments);
         viewBinding.viewPager.setAdapter(mineCoursePageAdapter);

+ 238 - 0
teacher/src/main/java/com/cooleshow/teacher/ui/course/VideoCourseFragment.java

@@ -0,0 +1,238 @@
+package com.cooleshow.teacher.ui.course;
+
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.PopupWindow;
+import android.widget.TextView;
+
+import com.bigkoo.pickerview.builder.TimePickerBuilder;
+import com.bigkoo.pickerview.listener.CustomListener;
+import com.bigkoo.pickerview.view.TimePickerView;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.listener.OnItemClickListener;
+import com.chad.library.adapter.base.listener.OnLoadMoreListener;
+import com.cooleshow.base.ui.fragment.BaseMVPFragment;
+import com.cooleshow.base.utils.LogUtils;
+import com.cooleshow.base.utils.PopupUtil;
+import com.cooleshow.base.utils.SizeUtils;
+import com.cooleshow.base.utils.TimeUtils;
+import com.cooleshow.teacher.R;
+import com.cooleshow.teacher.adapter.CourseStatusFilterAdapter;
+import com.cooleshow.teacher.adapter.SparringCourseListAdapter;
+import com.cooleshow.teacher.adapter.VideoCourseListAdapter;
+import com.cooleshow.teacher.bean.CourseFilterStatusBean;
+import com.cooleshow.teacher.bean.SparringCourseListBean;
+import com.cooleshow.teacher.bean.VideoCourseListBean;
+import com.cooleshow.teacher.constants.CourseFilterConstants;
+import com.cooleshow.teacher.contract.SparringCourseContract;
+import com.cooleshow.teacher.contract.VideoCourseContract;
+import com.cooleshow.teacher.databinding.FragmentSparringCourseLayoutBinding;
+import com.cooleshow.teacher.databinding.FragmentVideoCourseLayoutBinding;
+import com.cooleshow.teacher.presenter.course.SparringCoursePresenter;
+import com.cooleshow.teacher.presenter.course.VideoCoursePresenter;
+import com.cooleshow.teacher.widgets.VideoCourseListItemDecoration;
+import com.scwang.smart.refresh.layout.api.RefreshLayout;
+import com.scwang.smart.refresh.layout.listener.OnRefreshListener;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Author by pq, Date on 2022/4/25.
+ */
+public class VideoCourseFragment extends BaseMVPFragment<FragmentVideoCourseLayoutBinding, VideoCoursePresenter> implements VideoCourseContract.VideoCourseView, View.OnClickListener {
+    private int currentSubjectId;
+    private int currentPage;
+    private VideoCourseListAdapter mAdapter;
+    private View mEmptyView;
+    private TextView mTvEmptyTip;
+    private PopupWindow mPopupWindow;
+    private CourseStatusFilterAdapter mCourseStatusFilterAdapter;
+
+    @Override
+    protected FragmentVideoCourseLayoutBinding getLayoutView() {
+        return FragmentVideoCourseLayoutBinding.inflate(getLayoutInflater());
+    }
+
+    @Override
+    protected VideoCoursePresenter createPresenter() {
+        return new VideoCoursePresenter();
+    }
+
+    @Override
+    protected void initView(View rootView) {
+        mViewBinding.tvSubject.setOnClickListener(this);
+    }
+
+    private void buildDefaultCourseStatusFilterList() {
+//        mCourseFilterStatusBeans = new ArrayList<>();
+//        mCourseFilterStatusBeans.add(new CourseFilterStatusBean(CourseFilterConstants.COURSE_FILTER_ALL, "全部"));
+//        mCourseFilterStatusBeans.add(new CourseFilterStatusBean(CourseFilterConstants.COURSE_FILTER_HAS_NOT_STARTED, "未开始"));
+//        mCourseFilterStatusBeans.add(new CourseFilterStatusBean(CourseFilterConstants.COURSE_FILTER_IN_PROGRESS, "进行中"));
+//        mCourseFilterStatusBeans.add(new CourseFilterStatusBean(CourseFilterConstants.COURSE_FILTER_COMPLETED, "已结束"));
+    }
+
+    private void reBuildFilter() {
+        currentPage = 1;
+        queryCourse();
+    }
+
+
+    @Override
+    protected void initData() {
+        mViewBinding.refreshLayout.setOnRefreshListener(new OnRefreshListener() {
+            @Override
+            public void onRefresh(@NonNull RefreshLayout refreshLayout) {
+                currentPage = 1;
+                queryCourse();
+            }
+        });
+
+        mAdapter = new VideoCourseListAdapter(R.layout.item_video_course_list_layout);
+        mAdapter.getLoadMoreModule().setOnLoadMoreListener(new OnLoadMoreListener() {
+            @Override
+            public void onLoadMore() {
+                //上拉加载
+                currentPage++;
+                queryCourse();
+            }
+        });
+        GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), 2);
+        gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                int itemViewType = mAdapter.getItemViewType(position);
+                if (itemViewType == BaseQuickAdapter.LOAD_MORE_VIEW) {
+                    return 2;
+                }
+                return 1;
+            }
+        });
+        VideoCourseListItemDecoration itemDecoration = new VideoCourseListItemDecoration(0, SizeUtils.dp2px(11), 0, SizeUtils.dp2px(11), SizeUtils.dp2px(5.5f));
+        mViewBinding.recyclerView.addItemDecoration(itemDecoration);
+        mViewBinding.recyclerView.setLayoutManager(gridLayoutManager);
+        mViewBinding.recyclerView.setAdapter(mAdapter);
+        buildDefaultCourseStatusFilterList();
+        reBuildFilter();
+    }
+
+    private void queryCourse() {
+        //根据默认筛选条件查询
+        LogUtils.i("pq", "currentSubjectId:" + currentSubjectId);
+        LogUtils.i("pq", "currentPage:" + currentPage);
+        presenter.queryVideoCourse(currentSubjectId, currentPage);
+    }
+
+
+    @Override
+    public void onGetVideoCourseSuccess(int page, VideoCourseListBean liveCourseListBean) {
+        if (isDetached()) {
+            return;
+        }
+        if (liveCourseListBean != null) {
+            if (page == 1) {
+                //第一页
+                mViewBinding.refreshLayout.finishRefresh();
+                if (mAdapter != null) {
+                    mAdapter.getData().clear();
+                    mAdapter.notifyDataSetChanged();
+                    if (liveCourseListBean.rows != null && liveCourseListBean.rows.size() > 0) {
+                        mAdapter.setNewInstance(liveCourseListBean.rows);
+                    } else {
+                        showEmptyView();
+                    }
+                }
+            } else {
+                //加载更多
+                if (mAdapter != null) {
+                    if (liveCourseListBean.rows != null && liveCourseListBean.rows.size() > 0) {
+                        mAdapter.getLoadMoreModule().loadMoreComplete();
+                        mAdapter.addData(liveCourseListBean.rows);
+                    } else {
+                        mAdapter.getLoadMoreModule().loadMoreEnd(false);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onGetCourseError(int page) {
+        if (isDetached()) {
+            return;
+        }
+        if (page == 1) {
+            mViewBinding.refreshLayout.finishRefresh();
+        } else {
+            if (mAdapter != null) {
+                currentPage--;
+                mAdapter.getLoadMoreModule().loadMoreFail();
+            }
+        }
+    }
+
+    private void showEmptyView() {
+        if (mEmptyView == null) {
+            mEmptyView = getLayoutInflater().inflate(com.cooleshow.base.R.layout.empty_layout, mAdapter.getEmptyLayout(), false);
+            mTvEmptyTip = mEmptyView.findViewById(com.cooleshow.base.R.id.tv_empty_tip);
+        }
+        mTvEmptyTip.setText("暂无数据");
+        mAdapter.setEmptyView(mEmptyView);
+    }
+
+
+    private void initPopu(View targetView) {
+        if (mPopupWindow == null) {
+            View popupContentView = LayoutInflater.from(requireContext()).inflate(com.cooleshow.base.R.layout.list_popu_layout, null);
+            RecyclerView recyclerView = popupContentView.findViewById(R.id.recyclerView);
+            View bg = popupContentView.findViewById(com.cooleshow.base.R.id.view);
+            bg.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (mPopupWindow != null) {
+                        mPopupWindow.dismiss();
+                    }
+                }
+            });
+            mCourseStatusFilterAdapter = new CourseStatusFilterAdapter(com.cooleshow.base.R.layout.notice_popu_list_item);
+            mCourseStatusFilterAdapter.setOnItemClickListener(new OnItemClickListener() {
+                @Override
+                public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
+                    Object object = mCourseStatusFilterAdapter.getData().get(position);
+                    if (object instanceof CourseFilterStatusBean) {
+                        if (mCourseStatusFilterAdapter != null) {
+                            mCourseStatusFilterAdapter.setSelect(position);
+                        }
+                        CourseFilterStatusBean filterStatusBean = (CourseFilterStatusBean) object;
+                        mViewBinding.tvSubject.setText(filterStatusBean.showText);
+                        reBuildFilter();
+                    }
+                    mPopupWindow.dismiss();
+                }
+            });
+            recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
+            recyclerView.setAdapter(mCourseStatusFilterAdapter);
+//            mCourseStatusFilterAdapter.setNewInstance(mCourseFilterStatusBeans);
+            mPopupWindow = PopupUtil.createNoBackPopupWindow(popupContentView, requireContext(), ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT, true);
+        }
+        mPopupWindow.showAsDropDown(targetView);
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v.getId() == R.id.tv_course_status) {
+            //课程状态筛选
+            initPopu(mViewBinding.tvSubject);
+            return;
+        }
+    }
+}

+ 43 - 0
teacher/src/main/java/com/cooleshow/teacher/widgets/VideoCourseListItemDecoration.java

@@ -0,0 +1,43 @@
+package com.cooleshow.teacher.widgets;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * Author by pq, Date on 2021/3/18 0018.
+ */
+public class VideoCourseListItemDecoration extends RecyclerView.ItemDecoration {
+
+    private int top;
+    private int left;
+    private int bottom;
+    private int right;
+    private int center;
+
+    public VideoCourseListItemDecoration(int top, int left, int bottom, int right, int center) {
+        this.top = top;
+        this.left = left;
+        this.bottom = bottom;
+        this.right = right;
+        this.center = center;
+    }
+
+    @Override
+    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+        //每行都只有2个
+        int childLayoutPosition = parent.getChildLayoutPosition(view);
+        outRect.top = top;
+        outRect.bottom = bottom;
+        if (childLayoutPosition % 2 == 0) {
+            outRect.right = center;
+            outRect.left = left;
+        } else {
+            outRect.left = center;
+            outRect.right = right;
+        }
+    }
+}

+ 50 - 0
teacher/src/main/res/layout/fragment_video_course_layout.xml

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:ignore="MissingDefaultResource">
+
+    <TextView
+        android:id="@+id/tv_subject"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="25dp"
+        android:drawableRight="@drawable/icon_arrow_down"
+        android:drawablePadding="4dp"
+        android:gravity="center"
+        android:includeFontPadding="false"
+        android:paddingTop="18dp"
+        android:paddingBottom="12dp"
+        android:textColor="@color/color_666666"
+        android:textSize="@dimen/sp_13"
+        android:text="全部声部"
+        app:layout_constraintHorizontal_chainStyle="spread_inside"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        tools:text="全部声部" />
+
+
+    <com.scwang.smart.refresh.layout.SmartRefreshLayout
+        android:id="@+id/refreshLayout"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_subject">
+
+        <com.scwang.smart.refresh.header.ClassicsHeader
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/recyclerView"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:overScrollMode="never"
+            android:scrollbars="none" />
+    </com.scwang.smart.refresh.layout.SmartRefreshLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 103 - 0
teacher/src/main/res/layout/item_video_course_list_layout.xml

@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/bg_white_10dp"
+    android:layout_marginTop="12dp">
+
+    <com.cooleshow.base.widgets.QMUIRadiusImageView
+        android:id="@+id/iv_bg"
+        android:layout_width="match_parent"
+        android:layout_height="111dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:qmui_corner_radius="5dp" />
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:background="@drawable/bg_white_bottom_10dp"
+        app:layout_constraintBottom_toBottomOf="@+id/tv_price"
+        app:layout_constraintTop_toBottomOf="@+id/iv_bg" />
+
+    <TextView
+        android:id="@+id/tv_title"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="6dp"
+        android:includeFontPadding="false"
+        android:paddingStart="11dp"
+        android:paddingEnd="11dp"
+        android:textColor="@color/color_1a1a1a"
+        android:textSize="@dimen/sp_14"
+        android:textStyle="bold"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/iv_bg"
+        app:layout_constraintVertical_chainStyle="packed"
+        tools:text="张豆豆" />
+
+
+    <de.hdodenhof.circleimageview.CircleImageView
+        android:id="@+id/cir_avatar"
+        android:layout_width="18dp"
+        android:layout_height="18dp"
+        android:layout_marginStart="11dp"
+        android:layout_marginTop="9dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_title" />
+
+    <TextView
+        android:id="@+id/tv_author_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="5dp"
+        android:includeFontPadding="false"
+        android:textColor="@color/color_999999"
+        android:textSize="@dimen/sp_12"
+        app:layout_constraintBottom_toBottomOf="@+id/cir_avatar"
+        app:layout_constraintLeft_toRightOf="@+id/cir_avatar"
+        app:layout_constraintTop_toTopOf="@+id/cir_avatar"
+        tools:text="李老师" />
+
+    <View
+        android:id="@+id/view_line2"
+        android:layout_width="1dp"
+        android:layout_height="11dp"
+        android:layout_marginStart="8dp"
+        android:background="@color/color_d3d3d3"
+        android:visibility="visible"
+        app:layout_constraintBottom_toBottomOf="@+id/tv_author_name"
+        app:layout_constraintLeft_toRightOf="@+id/tv_author_name"
+        app:layout_constraintTop_toTopOf="@+id/tv_author_name" />
+
+    <TextView
+        android:id="@+id/tv_buy_num"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="8dp"
+        android:includeFontPadding="false"
+        android:textColor="@color/color_ff802c"
+        android:textSize="@dimen/sp_11"
+        android:visibility="visible"
+        app:layout_constraintBottom_toBottomOf="@+id/view_line2"
+        app:layout_constraintLeft_toRightOf="@+id/view_line2"
+        app:layout_constraintTop_toTopOf="@+id/view_line2"
+        tools:text="6人已购买" />
+
+    <TextView
+        android:id="@+id/tv_price"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="3dp"
+        android:paddingBottom="12dp"
+        android:textColor="@color/color_2dc7aa"
+        android:textSize="@dimen/sp_14"
+        android:textStyle="bold"
+        app:layout_constraintLeft_toLeftOf="@+id/cir_avatar"
+        app:layout_constraintTop_toBottomOf="@+id/cir_avatar"
+        tools:text="¥120/4课时" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>