瀏覽代碼

绘制首页布局

316044749 7 年之前
父節點
當前提交
878e6a3ae9
共有 23 個文件被更改,包括 1191 次插入19 次删除
  1. 4 0
      app/build.gradle
  2. 24 0
      app/src/main/AndroidManifest.xml
  3. 78 8
      app/src/main/java/com/ynstkz/shitu/android/activity/HomeActivity.java
  4. 41 0
      app/src/main/java/com/ynstkz/shitu/android/adapter/CourseNavigationGridAdapter.java
  5. 12 0
      app/src/main/java/com/ynstkz/shitu/android/base/BaseBean.java
  6. 12 1
      app/src/main/java/com/ynstkz/shitu/android/base/BaseFragment.java
  7. 12 0
      app/src/main/java/com/ynstkz/shitu/android/bean/CourseNavigationBean.java
  8. 65 0
      app/src/main/java/com/ynstkz/shitu/android/fragment/ConfirmationDialogFragment.java
  9. 61 1
      app/src/main/java/com/ynstkz/shitu/android/fragment/HomeFragment.java
  10. 26 0
      app/src/main/res/drawable/shape_search_bg.xml
  11. 0 2
      app/src/main/res/layout/activity_home.xml
  12. 46 1
      app/src/main/res/layout/fm_home.xml
  13. 55 0
      app/src/main/res/layout/view_home_title.xml
  14. 5 2
      app/src/main/res/values/colors.xml
  15. 1 1
      library/build.gradle
  16. 411 0
      library/src/main/java/com/common/library/adapter/CCAdapterHandler.java
  17. 32 0
      library/src/main/java/com/common/library/adapter/CCAdapterHolder.java
  18. 144 0
      library/src/main/java/com/common/library/adapter/CCListAdapter.java
  19. 110 0
      library/src/main/java/com/common/library/adapter/CCRecyclerAdapter.java
  20. 23 0
      library/src/main/java/com/common/library/adapter/CCRecyclerViewHolder.java
  21. 23 0
      library/src/main/java/com/common/library/adapter/CCViewAdapter.java
  22. 3 3
      library/src/main/res/values/pull_refresh_strings.xml
  23. 3 0
      library/src/main/res/values/strings.xml

+ 4 - 0
app/build.gradle

@@ -42,4 +42,8 @@ dependencies {
     compile 'com.jakewharton:butterknife:7.0.1'
     compile 'com.github.bumptech.glide:glide:3.7.0'
     compile 'com.muddzdev:styleabletoast:2.0.1'
+    //导航
+    compile 'com.amap.api:navi-3dmap:5.6.0_3dmap5.7.0'
+    //定位
+    compile 'com.amap.api:location:3.8.0'
 }

+ 24 - 0
app/src/main/AndroidManifest.xml

@@ -2,6 +2,26 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.ynstkz.shitu.android">
 
+    <uses-permission android:name="android.permission.INTERNET" />
+    <!--用于进行网络定位-->
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+    <!--用于访问GPS定位-->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <!--用于获取运营商信息,用于支持提供运营商信息相关的接口-->
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <!--用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+    <!--用于访问网络,网络定位需要上网-->
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <!--用于读取手机当前的状态-->
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <!--用于写入缓存数据到扩展存储卡-->
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <!--用于申请调用A-GPS模块-->
+    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
+
     <application
         android:name=".application.STApplication"
         android:allowBackup="true"
@@ -24,6 +44,10 @@
         <activity android:name=".activity.RegisterActivity"
             android:screenOrientation="portrait"/>
 
+        <!--定位服务-->
+        <meta-data android:name="com.ynstkz.shitu.android.demo" android:value="a78b553a67f68d1d980f908eb1f034a8"/>
+        <service android:name="com.amap.api.location.APSService"/>
+
     </application>
 
 </manifest>

+ 78 - 8
app/src/main/java/com/ynstkz/shitu/android/activity/HomeActivity.java

@@ -1,26 +1,36 @@
 package com.ynstkz.shitu.android.activity;
 
+import android.Manifest;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
 import android.support.v4.app.Fragment;
+import android.support.v4.content.ContextCompat;
+import android.util.Log;
 import android.view.View;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
-import android.widget.TextView;
 
+import com.amap.api.location.AMapLocation;
+import com.amap.api.location.AMapLocationClient;
+import com.amap.api.location.AMapLocationClientOption;
+import com.amap.api.location.AMapLocationListener;
 import com.ynstkz.shitu.android.R;
 import com.ynstkz.shitu.android.base.TitleBarActivity;
+import com.ynstkz.shitu.android.fragment.ConfirmationDialogFragment;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 import butterknife.Bind;
 import butterknife.ButterKnife;
 
-public class HomeActivity extends TitleBarActivity {
+public class HomeActivity extends TitleBarActivity implements AMapLocationListener {
+
+    private static final String FRAGMENT_DIALOG = "dialog";
+    private static final int REQUEST_CAMERA_PERMISSION = 1;
 
-    @Bind(R.id.tv_title)
-    TextView tvTitle;
-    @Bind(R.id.view_title)
-    RelativeLayout viewTitle;
     @Bind(R.id.rl_lab_home)
     RelativeLayout rlLabHome;
     @Bind(R.id.rl_lab_nearby)
@@ -33,6 +43,11 @@ public class HomeActivity extends TitleBarActivity {
     private Fragment[] mFragments;
     private int tabIndex;
 
+    //定位
+    public AMapLocationClient mlocationClient;
+    //声明mLocationOption对象
+    public AMapLocationClientOption mLocationOption = null;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -56,7 +71,19 @@ public class HomeActivity extends TitleBarActivity {
     }
 
     private void initData(){
-
+        mlocationClient = new AMapLocationClient(getApplicationContext());
+        //初始化定位参数
+        mLocationOption = new AMapLocationClientOption();
+        //设置定位监听
+        mlocationClient.setLocationListener(this);
+        //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
+        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving);
+        //获取一次定位结果:
+        mLocationOption.setOnceLocation(true);
+        //设置是否返回地址信息(默认返回地址信息)
+        mLocationOption.setNeedAddress(true);
+        //设置定位参数
+        mlocationClient.setLocationOption(mLocationOption);
     }
 
     private void setListener(){
@@ -101,6 +128,49 @@ public class HomeActivity extends TitleBarActivity {
         }
     }
 
+
+    @Override
+    public void onLocationChanged(AMapLocation amapLocation) {
+        if (amapLocation != null) {
+            if (amapLocation.getErrorCode() == 0) {
+                //定位成功回调信息,设置相关消息
+                amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
+                amapLocation.getLatitude();//获取纬度
+                amapLocation.getLongitude();//获取经度
+                amapLocation.getAccuracy();//获取精度信息
+                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                Date date = new Date(amapLocation.getTime());
+                df.format(date);//定位时间
+            } else {
+                //显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
+                Log.e("AmapError", "location Error, ErrCode:"
+                        + amapLocation.getErrorCode() + ", errInfo:"
+                        + amapLocation.getErrorInfo());
+            }
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
+                == PackageManager.PERMISSION_GRANTED) {
+            //启动定位
+            mlocationClient.startLocation();
+        } else if (ActivityCompat.shouldShowRequestPermissionRationale(this,
+                Manifest.permission.ACCESS_COARSE_LOCATION)){
+            ConfirmationDialogFragment
+                    .newInstance(R.string.app_name,
+                            new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
+                            REQUEST_CAMERA_PERMISSION,
+                            R.string.app_name)
+                    .show(getSupportFragmentManager(), FRAGMENT_DIALOG);
+        } else {
+            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
+                    REQUEST_CAMERA_PERMISSION);
+        }
+    }
+
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         switch (requestCode) {

+ 41 - 0
app/src/main/java/com/ynstkz/shitu/android/adapter/CourseNavigationGridAdapter.java

@@ -0,0 +1,41 @@
+package com.ynstkz.shitu.android.adapter;
+
+import android.content.Context;
+import android.view.View;
+
+import com.common.library.adapter.CCAdapterHolder;
+import com.common.library.adapter.CCListAdapter;
+import com.ynstkz.shitu.android.bean.CourseNavigationBean;
+
+import java.util.List;
+
+/**
+ * 作者:fuchangle on 2018/2/6 14:37
+ */
+
+public class CourseNavigationGridAdapter extends CCListAdapter<CourseNavigationBean>{
+
+    public CourseNavigationGridAdapter(Context context, List<CourseNavigationBean> adapterContent) {
+        super(context, adapterContent);
+    }
+
+    @Override
+    public CCAdapterHolder<CourseNavigationBean> createHolder(int type) {
+        return new CCAdapterHolder<CourseNavigationBean>() {
+            @Override
+            public int getResource() {
+                return 0;
+            }
+
+            @Override
+            public void initializeView(View convertView) {
+
+            }
+
+            @Override
+            public void updateView(CourseNavigationBean content, int position) {
+
+            }
+        };
+    }
+}

+ 12 - 0
app/src/main/java/com/ynstkz/shitu/android/base/BaseBean.java

@@ -0,0 +1,12 @@
+package com.ynstkz.shitu.android.base;
+
+import java.io.Serializable;
+
+/**
+ * 作者:fuchangle on 2018/2/6 14:38
+ */
+
+public class BaseBean implements Serializable{
+
+
+}

+ 12 - 1
app/src/main/java/com/ynstkz/shitu/android/base/BaseFragment.java

@@ -1,5 +1,7 @@
 package com.ynstkz.shitu.android.base;
 
+import android.content.Context;
+import android.graphics.Color;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
@@ -7,6 +9,8 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.muddzdev.styleabletoastlibrary.StyleableToast;
+
 /**
  * 作者:fuchangle on 2018/1/29 11:38
  */
@@ -19,5 +23,12 @@ public class BaseFragment extends Fragment{
         return super.onCreateView(inflater, container, savedInstanceState);
     }
 
-
+    protected void showToast(Context context, String content){
+        new StyleableToast
+                .Builder(context)
+                .text(content)
+                .textColor(Color.WHITE)
+                .backgroundColor(Color.BLACK)
+                .show();
+    }
 }

+ 12 - 0
app/src/main/java/com/ynstkz/shitu/android/bean/CourseNavigationBean.java

@@ -0,0 +1,12 @@
+package com.ynstkz.shitu.android.bean;
+
+import com.ynstkz.shitu.android.base.BaseBean;
+
+/**
+ * 作者:fuchangle on 2018/2/6 14:37
+ */
+
+public class CourseNavigationBean extends BaseBean{
+
+
+}

+ 65 - 0
app/src/main/java/com/ynstkz/shitu/android/fragment/ConfirmationDialogFragment.java

@@ -0,0 +1,65 @@
+package com.ynstkz.shitu.android.fragment;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.app.AlertDialog;
+import android.widget.Toast;
+
+/**
+ * 作者:fuchangle on 2017/10/9 18:09
+ */
+
+public class ConfirmationDialogFragment extends DialogFragment{
+
+    private static final String ARG_MESSAGE = "message";
+    private static final String ARG_PERMISSIONS = "permissions";
+    private static final String ARG_REQUEST_CODE = "request_code";
+    private static final String ARG_NOT_GRANTED_MESSAGE = "not_granted_message";
+
+    public static ConfirmationDialogFragment newInstance(@StringRes int message,
+                                                         String[] permissions, int requestCode, @StringRes int notGrantedMessage) {
+        ConfirmationDialogFragment fragment = new ConfirmationDialogFragment();
+        Bundle args = new Bundle();
+        args.putInt(ARG_MESSAGE, message);
+        args.putStringArray(ARG_PERMISSIONS, permissions);
+        args.putInt(ARG_REQUEST_CODE, requestCode);
+        args.putInt(ARG_NOT_GRANTED_MESSAGE, notGrantedMessage);
+        fragment.setArguments(args);
+        return fragment;
+    }
+
+    @NonNull
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        final Bundle args = getArguments();
+        return new AlertDialog.Builder(getActivity())
+                .setMessage(args.getInt(ARG_MESSAGE))
+                .setPositiveButton(android.R.string.ok,
+                        new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                String[] permissions = args.getStringArray(ARG_PERMISSIONS);
+                                if (permissions == null) {
+                                    throw new IllegalArgumentException();
+                                }
+                                ActivityCompat.requestPermissions(getActivity(),
+                                        permissions, args.getInt(ARG_REQUEST_CODE));
+                            }
+                        })
+                .setNegativeButton(android.R.string.cancel,
+                        new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                Toast.makeText(getActivity(),
+                                        args.getInt(ARG_NOT_GRANTED_MESSAGE),
+                                        Toast.LENGTH_SHORT).show();
+                            }
+                        })
+                .create();
+    }
+}

+ 61 - 1
app/src/main/java/com/ynstkz/shitu/android/fragment/HomeFragment.java

@@ -1,23 +1,83 @@
 package com.ynstkz.shitu.android.fragment;
 
 import android.os.Bundle;
+import android.support.v4.view.ViewPager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.GridView;
+import android.widget.ScrollView;
+import android.widget.TextView;
 
+import com.common.library.pulltorefresh.PullToRefreshBase;
+import com.common.library.pulltorefresh.PullToRefreshScrollView;
 import com.ynstkz.shitu.android.R;
 import com.ynstkz.shitu.android.base.BaseFragment;
 
+import butterknife.Bind;
+import butterknife.ButterKnife;
+
 /**
  * 作者:fuchangle on 2018/1/29 11:38
  */
 
-public class HomeFragment extends BaseFragment{
+public class HomeFragment extends BaseFragment implements PullToRefreshBase.OnRefreshListener2<ScrollView> {
+
+    @Bind(R.id.tv_location)
+    TextView tvLocation;
+    @Bind(R.id.viewpager)
+    ViewPager viewpager;
+    @Bind(R.id.gv_course_navigation)
+    GridView gvCourseNavigation;
+    @Bind(R.id.sv_main)
+    PullToRefreshScrollView svMain;
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.fm_home, null);
+        ButterKnife.bind(this, view);
+        initView();
+        setListener();
         return view;
     }
 
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        ButterKnife.unbind(this);
+    }
+
+    private void initView() {
+        svMain.setOnRefreshListener(this);
+    }
+
+    private void setListener() {
+
+        viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+            @Override
+            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+
+            }
+
+            @Override
+            public void onPageSelected(int position) {
+
+            }
+
+            @Override
+            public void onPageScrollStateChanged(int state) {
+
+            }
+        });
+    }
+
+    @Override
+    public void onPullDownToRefresh(PullToRefreshBase<ScrollView> refreshView) {
+        showToast(getActivity(), "onPullDownToRefresh");
+    }
+
+    @Override
+    public void onPullUpToRefresh(PullToRefreshBase<ScrollView> refreshView) {
+        showToast(getActivity(), "onPullUpToRefresh");
+    }
 }

+ 26 - 0
app/src/main/res/drawable/shape_search_bg.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- 填充的颜色 -->
+
+    <solid android:color="@color/white" />
+
+    <!-- 设置边框宽度 -->
+    <!--<stroke android:width="1dp" android:color="#999999"/>-->
+
+    <!-- 四个角的弧度 -->
+    <corners
+        android:bottomLeftRadius="50dp"
+        android:bottomRightRadius="50dp"
+        android:topLeftRadius="50dp"
+        android:topRightRadius="50dp" />
+    <!-- padding:TextView里面的文字与TextView边界的间隔 -->
+
+    <padding
+        android:bottom="5dp"
+        android:left="2dp"
+        android:right="2dp"
+        android:top="5dp" />
+    <!-- <size android:width="100dp" android:height="45dp"/> -->
+
+</shape>

+ 0 - 2
app/src/main/res/layout/activity_home.xml

@@ -10,8 +10,6 @@
         android:layout_alignParentTop="true"
         android:layout_above="@+id/ll_bottom_lab">
 
-        <include layout="@layout/view_title"/>
-
         <fragment
             android:id="@+id/fm_home"
             android:name="com.ynstkz.shitu.android.fragment.HomeFragment"

+ 46 - 1
app/src/main/res/layout/fm_home.xml

@@ -2,6 +2,51 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:background="@color/default_bg">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="?attr/actionBarSize"
+        android:orientation="vertical">
+
+        <include layout="@layout/view_home_title"/>
+
+    </LinearLayout>
+
+    <com.common.library.pulltorefresh.PullToRefreshScrollView
+        android:id="@+id/sv_main"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+       <LinearLayout
+           android:layout_width="match_parent"
+           android:layout_height="wrap_content"
+           android:orientation="vertical">
+
+           <RelativeLayout
+               android:layout_width="match_parent"
+               android:layout_height="200dp"
+               android:background="@color/white">
+
+               <android.support.v4.view.ViewPager
+                   android:id="@+id/viewpager"
+                   android:layout_width="300dp"
+                   android:layout_height="match_parent"
+                   android:layout_centerInParent="true"
+                   android:clipChildren="false"/>
+
+           </RelativeLayout>
+
+           <GridView
+               android:id="@+id/gv_course_navigation"
+               android:layout_width="match_parent"
+               android:layout_height="wrap_content"
+               android:background="@color/white"
+               android:numColumns="4"/>
+
+       </LinearLayout>
+
+    </com.common.library.pulltorefresh.PullToRefreshScrollView>
 
 </LinearLayout>

+ 55 - 0
app/src/main/res/layout/view_home_title.xml

@@ -0,0 +1,55 @@
+<?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:orientation="horizontal"
+    android:background="@color/main_color">
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_weight="2"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:gravity="center">
+
+        <ImageView
+            android:layout_width="@dimen/company_20dp"
+            android:layout_height="@dimen/company_20dp"
+            android:background="@mipmap/ic_launcher"
+            />
+
+        <TextView
+            android:id="@+id/tv_location"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxLines="1"
+            android:ellipsize="end"
+            android:textSize="@dimen/company_16sp"
+            android:textColor="@color/white"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_weight="7"
+        android:layout_height="@dimen/company_35dp"
+        android:background="@drawable/shape_search_bg"
+        android:layout_gravity="center">
+
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_weight="2"
+        android:layout_height="match_parent"
+        android:gravity="center">
+
+        <ImageView
+            android:layout_width="@dimen/company_40dp"
+            android:layout_height="@dimen/company_40dp"
+            android:background="@mipmap/ic_launcher"/>
+
+    </LinearLayout>
+
+</LinearLayout>

+ 5 - 2
app/src/main/res/values/colors.xml

@@ -1,10 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <color name="colorPrimary">#3F51B5</color>
-    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorPrimary">#3791f6</color>
+    <color name="colorPrimaryDark">#3791f6</color>
     <color name="colorAccent">#FF4081</color>
+    <color name="main_color">#3791f6</color>
 
     <color name="black">#000000</color>
     <color name="white">#ffffff</color>
     <color name="translucence">#0e000000</color>
+
+    <color name="default_bg">#F0F0F0</color>
 </resources>

+ 1 - 1
library/build.gradle

@@ -23,7 +23,7 @@ android {
 
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
-
+    compile 'com.android.support:recyclerview-v7:26.1.0'
     compile 'com.android.support:appcompat-v7:26.1.0'
     compile 'com.squareup.okhttp3:okhttp:3.3.1'
 }

+ 411 - 0
library/src/main/java/com/common/library/adapter/CCAdapterHandler.java

@@ -0,0 +1,411 @@
+package com.common.library.adapter;
+
+import android.widget.BaseAdapter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ * A handler to control content. <br/>
+ * Every modification of content will call {@link BaseAdapter#notifyDataSetChanged()} automatically.
+ *
+ * Created by yanhaifeng on 16-7-27.
+ */
+
+public class CCAdapterHandler<T> extends ArrayList<T> {
+
+    private ContentObserver mContentObserver;
+
+    private Transaction<T> mTransaction;
+
+    public CCAdapterHandler() {
+        super();
+    }
+
+    public CCAdapterHandler(Collection<T> collection) {
+        super(collection);
+    }
+
+    void setContentObserver(ContentObserver contentObserver) {
+        mContentObserver = contentObserver;
+    }
+
+    public Transaction<T> beginTransation() {
+        mTransaction = new Transaction<T>(this);
+        return mTransaction;
+    }
+
+    public void endTransaction() {
+        mTransaction = null;
+    }
+
+    @Override
+    public boolean add(T object) {
+        try {
+            return super.add(object);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public void add(int index, T object) {
+        try {
+            super.add(index, object);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends T> collection) {
+        try {
+            return super.addAll(collection);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public boolean addAll(int index, Collection<? extends T> collection) {
+        try {
+            return super.addAll(index, collection);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public T set(int index, T object) {
+        try {
+            return super.set(index, object);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    public void set(T object) {
+        try {
+            super.clear();
+            super.add(object);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    public void set(Collection<T> collection) {
+        try {
+            super.clear();
+            super.addAll(collection);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public boolean remove(Object object) {
+        try {
+            return super.remove(object);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public T remove(int index) {
+        try {
+            return super.remove(index);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public void removeRange(int fromIndex, int toIndex) {
+        try {
+            super.removeRange(fromIndex, toIndex);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> collection) {
+        try {
+            return super.removeAll(collection);
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    @Override
+    public void clear() {
+        try {
+            super.clear();
+        } finally {
+            notifyObserver();
+        }
+    }
+
+    private void notifyObserver() {
+        if (mTransaction == null) {
+            notifyObserverActually();
+        }
+    }
+
+    private void notifyObserverActually() {
+        if (mContentObserver != null) {
+            try {
+                mContentObserver.onContentChanged();
+            } catch (Throwable t) {
+                t.printStackTrace();
+            }
+        }
+    }
+
+    interface ContentObserver {
+
+        void onContentChanged();
+
+    }
+
+    public static class Transaction<T> {
+
+        private CCAdapterHandler<T> mAdapterHandler;
+        private LinkedList<Operation<T>> mOperations = new LinkedList<Operation<T>>();
+
+        public Transaction(CCAdapterHandler<T> adapterHandler) {
+            mAdapterHandler = adapterHandler;
+        }
+
+        public Transaction add(T object) {
+            mOperations.add(new AddOperation<T>(object));
+            return this;
+        }
+
+        public Transaction add(int index, T object) {
+            mOperations.add(new AddOperation<T>(object, index));
+            return this;
+        }
+
+        public Transaction addAll(Collection<T> collection) {
+            mOperations.add(new AddAllOperation<T>(collection));
+            return this;
+        }
+
+        public Transaction addAll(int index, Collection<T> collection) {
+            mOperations.add(new AddAllOperation<T>(collection, index));
+            return this;
+        }
+
+        public Transaction set(int index, T object) {
+            mOperations.add(new SetOperation<T>(object, index));
+            return this;
+        }
+
+        public Transaction set(Collection<T> collection) {
+            mOperations.add(new SetAllOperation<T>(collection));
+            return this;
+        }
+
+        public Transaction remove(T object) {
+            mOperations.add(new RemoveOperation<T>(object));
+            return this;
+        }
+
+        public Transaction remove(int index) {
+            mOperations.add(new RemoveIndexOperation<T>(index));
+            return this;
+        }
+
+        protected Transaction removeRange(int fromIndex, int toIndex) {
+            mOperations.add(new RemoveRangeOperation<T>(fromIndex, toIndex));
+            return this;
+        }
+
+        public Transaction removeAll(Collection<T> collection) {
+            mOperations.add(new RemoveAllOperation<T>(collection));
+            return this;
+        }
+
+        public Transaction clear() {
+            mOperations.add(new ClearOperation<T>());
+            return this;
+        }
+
+        public void commitAndEnd() {
+            try {
+                for (Operation<T> operation : mOperations) {
+                    operation.doOperation(mAdapterHandler);
+                }
+                mAdapterHandler.notifyObserverActually();
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                mAdapterHandler.endTransaction();
+            }
+        }
+
+        interface Operation<T> {
+
+            void doOperation(CCAdapterHandler<T> handler);
+        }
+
+        static class AddOperation<T> implements Operation<T> {
+
+            private T element;
+
+            private int position = -1;
+
+            public AddOperation(T element) {
+                this.element = element;
+            }
+
+            public AddOperation(T element, int position) {
+                this.element = element;
+                this.position = position;
+            }
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                if (position == -1) {
+                    handler.add(element);
+                } else {
+                    handler.add(position, element);
+                }
+            }
+        }
+
+        static class AddAllOperation<T> implements Operation<T> {
+
+            private Collection<T> elements;
+
+            private int position = -1;
+
+            public AddAllOperation(Collection<T> elements) {
+                this.elements = elements;
+            }
+
+            public AddAllOperation(Collection<T> elements, int position) {
+                this.elements = elements;
+                this.position = position;
+            }
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                if (position == -1) {
+                    handler.addAll(elements);
+                } else {
+                    handler.addAll(position, elements);
+                }
+            }
+        }
+
+        static class SetOperation<T> implements Operation<T> {
+
+            private T element;
+
+            private int position = -1;
+
+            public SetOperation(T element) {
+                this.element = element;
+            }
+
+            public SetOperation(T element, int position) {
+                this.element = element;
+                this.position = position;
+            }
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                if (position == -1) {
+                    handler.set(element);
+                } else {
+                    handler.set(position, element);
+                }
+            }
+        }
+
+        static class SetAllOperation<T> implements Operation<T> {
+
+            private Collection<T> elements;
+
+            public SetAllOperation(Collection<T> elements) {
+                this.elements = elements;
+            }
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                handler.set(elements);
+            }
+        }
+
+        static class RemoveOperation<T> implements Operation<T> {
+
+            private T element;
+
+            public RemoveOperation(T element) {
+                this.element = element;
+            }
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                handler.remove(element);
+            }
+        }
+
+        static class RemoveIndexOperation<T> implements Operation<T> {
+
+            private int position = -1;
+
+            public RemoveIndexOperation(int position) {
+                this.position = position;
+            }
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                handler.remove(position);
+            }
+        }
+
+        static class RemoveRangeOperation<T> implements Operation<T> {
+
+            private int fromIndex;
+            private int toIndex;
+
+            public RemoveRangeOperation(int fromIndex, int toIndex) {
+                this.fromIndex = fromIndex;
+                this.toIndex = toIndex;
+            }
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                handler.removeRange(fromIndex, toIndex);
+            }
+        }
+
+        static class RemoveAllOperation<T> implements Operation<T> {
+
+            private Collection<T> elements;
+
+            public RemoveAllOperation(Collection<T> elements) {
+                this.elements = elements;
+            }
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                handler.removeAll(elements);
+            }
+        }
+
+        static class ClearOperation<T> implements Operation<T> {
+
+            @Override
+            public void doOperation(CCAdapterHandler<T> handler) {
+                handler.clear();
+            }
+        }
+
+    }
+}

+ 32 - 0
library/src/main/java/com/common/library/adapter/CCAdapterHolder.java

@@ -0,0 +1,32 @@
+package com.common.library.adapter;
+
+import android.view.View;
+
+/**
+ * Created by yanhaifeng on 16-7-27.
+ */
+
+public interface CCAdapterHolder<T> {
+
+    /**
+     * Decide which layout to display.
+     *
+     * @return Item layout id.
+     */
+    int getResource();
+
+    /**
+     * Initialize views in layout.
+     *
+     * @param convertView Layout view.
+     */
+    void initializeView(View convertView);
+
+    /**
+     * Update layout views by content.
+     *
+     * @param content Item content.
+     * @param position Item position.
+     */
+    void updateView(T content, int position);
+}

+ 144 - 0
library/src/main/java/com/common/library/adapter/CCListAdapter.java

@@ -0,0 +1,144 @@
+package com.common.library.adapter;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+
+import com.common.library.R;
+
+import java.util.List;
+
+/**
+ * Created by yanhaifeng on 16-7-27.
+ */
+
+public abstract class CCListAdapter<T> extends BaseAdapter implements CCViewAdapter<T> {
+
+    private List<T> mAdapterContent;
+
+    private Context mContext;
+
+    private LayoutInflater mLayoutInflater;
+
+    /**
+     * Construct list adapter.
+     *
+     * @param context Context.
+     * @param adapterContent Content to display.
+     */
+    public CCListAdapter(Context context, List<T> adapterContent) {
+        if (adapterContent != null && adapterContent instanceof CCAdapterHandler) {
+            ((CCAdapterHandler) adapterContent).setContentObserver(new CCAdapterHandler.ContentObserver() {
+                @Override
+                public void onContentChanged() {
+                    notifyDataSetChanged();
+                }
+            });
+        }
+        mContext = context;
+        mAdapterContent = adapterContent;
+        mLayoutInflater = LayoutInflater.from(context);
+    }
+
+    /**
+     * set adapterContent.
+     *
+     * @param adapterContent Content to display.
+     */
+    public void setAdapterContent(List<T> adapterContent) {
+        this.mAdapterContent = adapterContent;
+    }
+
+    /**
+     * To update a item view, avoid calling {@link BaseAdapter#notifyDataSetChanged()} to refresh all items.
+     *
+     * @param listView ListView to update item.
+     * @param index Item index.
+     */
+    public void updateItemView(ListView listView, int index) {
+        int firstVisibleItemIndex = listView.getFirstVisiblePosition();
+        int lastVisibleItemIndex = listView.getLastVisiblePosition();
+        if (index >= firstVisibleItemIndex && index <= lastVisibleItemIndex) {
+            View view = listView.getChildAt(index - firstVisibleItemIndex);
+            updateView(index, view);
+        }
+    }
+
+    @Override
+    public int getCount() {
+        if (mAdapterContent == null) {
+            return 0;
+        }
+        return mAdapterContent.size();
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return mAdapterContent.get(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (convertView == null) {
+            convertView = createView(position, parent);
+        }
+        updateView(position, convertView);
+        return convertView;
+    }
+
+    @NonNull
+    protected final View createView(int position, ViewGroup parent) {
+        CCAdapterHolder<T> holder = createHolder(getItemViewType(position));
+        View view = createView(parent, holder, position);
+        if (view != null) {
+            holder.initializeView(view);
+            view.setTag(R.string.cc_adapter_holder_tag_key, holder);
+            return view;
+        }
+        return view;
+    }
+
+    protected View createView(ViewGroup parent, CCAdapterHolder<T> holder, int position) {
+        return mLayoutInflater.inflate(holder.getResource(), parent, false);
+    }
+
+    protected void updateView(int position, View convertView) {
+        CCAdapterHolder<T> holder = getHolder(convertView);
+        if (holder != null) {
+            convertView.setTag(R.string.cc_adapter_holder_index_tag_key, position);
+            holder.updateView((T) getItem(position), position);
+        }
+    }
+
+    @Override
+    public CCAdapterHolder<T> getHolder(View convertView) {
+        return (CCAdapterHolder<T>) convertView.getTag(R.string.cc_adapter_holder_tag_key);
+    }
+
+    @Override
+    public int getPosition(View convertView) {
+        return (Integer) convertView.getTag(R.string.cc_adapter_holder_index_tag_key);
+    }
+
+    protected Context getContext() {
+        return mContext;
+    }
+
+    protected LayoutInflater getLayoutInflater() {
+        return mLayoutInflater;
+    }
+
+    public List<T> getItems() {
+        return mAdapterContent;
+    }
+
+}

+ 110 - 0
library/src/main/java/com/common/library/adapter/CCRecyclerAdapter.java

@@ -0,0 +1,110 @@
+package com.common.library.adapter;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.common.library.R;
+
+import java.util.List;
+
+/**
+ * <br/><br/>
+ * Created by Yanhaifeng on 2017/6/19.
+ */
+
+public abstract class CCRecyclerAdapter<T> extends RecyclerView.Adapter<CCRecyclerViewHolder> implements CCViewAdapter<T> {
+
+    private Context mContext;
+    private List<T> mAdapterContent;
+    private LayoutInflater mLayoutInflater;
+
+    private boolean mIsLooped;
+    private int mLoopFactor;
+
+    public CCRecyclerAdapter(Context context, List<T> adapterContent) {
+        mContext = context;
+        if (adapterContent instanceof CCAdapterHandler) {
+            ((CCAdapterHandler) adapterContent).setContentObserver(new CCAdapterHandler.ContentObserver() {
+                @Override
+                public void onContentChanged() {
+                    notifyDataSetChanged();
+                }
+            });
+        }
+        mAdapterContent = adapterContent;
+        mLayoutInflater = LayoutInflater.from(context);
+    }
+
+    public void setLooped(boolean isLooped) {
+        setLooped(isLooped, -1);
+    }
+
+    public void setLooped(boolean isLooped, int factor) {
+        mIsLooped = isLooped;
+        mLoopFactor = factor;
+    }
+
+    public int getRealPositionInLoop(int loopedPosition) {
+        return loopedPosition % mAdapterContent.size();
+    }
+
+    public int getLoopedInitializePosition() {
+        int halfSize = getLoopedSize() / 2;
+        return halfSize - halfSize % mAdapterContent.size();
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public CCRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        CCAdapterHolder<T> holder = createHolder(viewType);
+        View convertView = mLayoutInflater.inflate(holder.getResource(), parent, false);
+        holder.initializeView(convertView);
+        return new CCRecyclerViewHolder(convertView, holder);
+    }
+
+    @Override
+    public void onBindViewHolder(CCRecyclerViewHolder holder, int position) {
+        position %= mAdapterContent.size();
+        View itemView = holder.itemView;
+        CCAdapterHolder adapterHolder = holder.getAdapterHolder();
+        itemView.setTag(R.string.cc_adapter_holder_tag_key, adapterHolder);
+        itemView.setTag(R.string.cc_adapter_holder_index_tag_key, position);
+        adapterHolder.updateView(mAdapterContent.get(position), position);
+    }
+
+    @Override
+    public int getItemCount() {
+        if (mAdapterContent == null) {
+            return 0;
+        }
+        return getLoopedSize();
+    }
+
+    private int getLoopedSize() {
+        int size = mAdapterContent.size();
+        if (mIsLooped) {
+            if (mLoopFactor == -1) {
+                size = Integer.MAX_VALUE;
+            } else {
+                size *= Math.max(0, mLoopFactor);
+            }
+        }
+        return size;
+    }
+
+    @Override
+    public CCAdapterHolder<T> getHolder(View convertView) {
+        return (CCAdapterHolder<T>) convertView.getTag(R.string.cc_adapter_holder_tag_key);
+    }
+
+    @Override
+    public int getPosition(View convertView) {
+        return (Integer) convertView.getTag(R.string.cc_adapter_holder_index_tag_key);
+    }
+}

+ 23 - 0
library/src/main/java/com/common/library/adapter/CCRecyclerViewHolder.java

@@ -0,0 +1,23 @@
+package com.common.library.adapter;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+/**
+ * <br/><br/>
+ * Created by Yanhaifeng on 2017/6/19.
+ */
+
+class CCRecyclerViewHolder<T> extends RecyclerView.ViewHolder {
+
+    private CCAdapterHolder<T> mAdapterHolder;
+
+    public CCRecyclerViewHolder(View itemView, CCAdapterHolder<T> holder) {
+        super(itemView);
+        mAdapterHolder = holder;
+    }
+
+    public CCAdapterHolder<T> getAdapterHolder() {
+        return mAdapterHolder;
+    }
+}

+ 23 - 0
library/src/main/java/com/common/library/adapter/CCViewAdapter.java

@@ -0,0 +1,23 @@
+package com.common.library.adapter;
+
+import android.view.View;
+
+/**
+ * <br/><br/>
+ * Created by Yanhaifeng on 2017/6/19.
+ */
+
+public interface CCViewAdapter<T> {
+
+    /**
+     * Create the holder of item layout base on the type.
+     *
+     * @param type Item type
+     * @return Holder with item layout.
+     */
+    CCAdapterHolder<T> createHolder(int type);
+
+    CCAdapterHolder<T> getHolder(View convertView);
+
+    int getPosition(View convertView);
+}

+ 3 - 3
library/src/main/res/values/pull_refresh_strings.xml

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <string name="pull_to_refresh_pull_label">Pull to refresh…</string>
-    <string name="pull_to_refresh_release_label">Release to refresh…</string>
-    <string name="pull_to_refresh_refreshing_label">Loading…</string>
+    <string name="pull_to_refresh_pull_label">下拉刷新…</string>
+    <string name="pull_to_refresh_release_label">放开以刷新…</string>
+    <string name="pull_to_refresh_refreshing_label">正在载入…</string>
 
     <!-- Just use standard Pull Down String when pulling up. These can be set for languages which require it -->
     <string name="pull_to_refresh_from_bottom_pull_label">@string/pull_to_refresh_pull_label</string>

+ 3 - 0
library/src/main/res/values/strings.xml

@@ -1,3 +1,6 @@
 <resources>
     <string name="app_name">library</string>
+    <string name="cc_adapter_holder_tag_key">cc_adapter_holder_tag_key</string>
+    <string name="cc_adapter_holder_index_tag_key">cc_adapter_holder_index_tag_key</string>
+
 </resources>