项目开发框架搭建二

来源:互联网 发布:g11s变频器的数据复写 编辑:程序博客网 时间:2024/05/18 15:08

这里写图片描述

主MainActivity-activity.main.xml

这里写图片描述

<?xml version="1.0" encoding="utf-8"?><com.zhy.autolayout.AutoLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">      <history.six.com.rushingdemo.view.LazyViewPager          android:layout_width="match_parent"          android:layout_height="0px"          android:layout_weight="1"          android:id="@+id/main_lazyViewPager">      </history.six.com.rushingdemo.view.LazyViewPager>    <RadioGroup        android:id="@+id/rg"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_gravity="bottom"        android:background="@mipmap/bottom"        android:gravity="center_vertical"        android:paddingTop="10px"        android:paddingBottom="10px"        android:orientation="horizontal">        <RadioButton            android:id="@+id/rb_home"            android:layout_width="0dp"            android:checked="true"            android:layout_height="wrap_content"            android:layout_weight="1"            android:background="#f5f5f5"            android:button="@null"            android:drawableTop="@drawable/duobao_selector"            android:gravity="center"            android:textColor="@drawable/bottom_text_color"            android:text="夺宝" />        <RadioButton            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="#f5f5f5"            android:button="@null"            android:drawableTop="@drawable/category_selector"            android:gravity="center"            android:text="分类"            android:textColor="@drawable/bottom_text_color"/>        <RadioButton            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="#f5f5f5"            android:button="@null"            android:drawableTop="@drawable/newjiexiao_selector"            android:gravity="center"            android:text="最新揭晓"            android:textColor="@drawable/bottom_text_color"/>        <RadioButton            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="#f5f5f5"            android:button="@null"            android:drawableTop="@drawable/order_selector"            android:gravity="center"            android:text="订单"            android:textColor="@drawable/bottom_text_color"/>        <RadioButton            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            android:background="#f5f5f5"            android:button="@null"            android:drawableTop="@drawable/mine_selector"            android:gravity="center"            android:text="我的"            android:textColor="@drawable/bottom_text_color"            android:id="@+id/radioButton" />    </RadioGroup></com.zhy.autolayout.AutoLinearLayout>

Build.gradle依赖

//屏幕适配依赖    compile 'com.zhy:autolayout:1.4.5'    //android5.0控件的使用依赖    compile 'com.android.support:design:25.1.1'    //retrofit网络访问    compile 'com.squareup.retrofit2:retrofit:2.0.0-beta2'    compile 'com.squareup.retrofit2:converter-scalars:2.0.0'    compile 'com.squareup.retrofit2:converter-gson:2.1.0'    //fresco图片加载      compile 'com.github.CarGuo:FrescoUtils:v1.0.4'  compile project(':library')    //轮播图    compile 'com.youth.banner:banner:1.4.8'    //Glide图片加载    compile 'com.github.bumptech.glide:glide:3.7.0'

整体布局格式

这里写图片描述

MyApplication

package history.six.com.rushingdemo.application;import android.app.Application;import android.content.Context;import android.os.Handler;import android.os.Process;import com.facebook.drawee.backends.pipeline.Fresco;import com.facebook.imagepipeline.core.ImagePipelineConfig;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class MyApplication extends Application {    private static Context context;    private static Handler handler;    private static int mainThreadId;    private static Thread currentThread;    private static ExecutorService executorService;    @Override    public void onCreate() {        super.onCreate();        /**         * 初始化Fresco         */        ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)                .setDownsampleEnabled(true)                .build();        Fresco.initialize(this, config);        context = getApplicationContext();        //获取handler        handler = new Handler();        //获取主线程id        mainThreadId = Process.myTid();        //获取当前线程        currentThread = Thread.currentThread();        //创建线程池        executorService = Executors.newFixedThreadPool(5);    }    /**     * 获取整个应用的上下文     */    public static Context getContext(){        return context;    }    public static ExecutorService getThreadPoll() {        return executorService;    }    public static Thread getMainThread() {        return currentThread;    }    public static int getMainThreadId() {        return mainThreadId;    }    public static Handler getHandler() {        return handler;    }}

**

BaseData

//1.网络缓存数据存放的路径

//2.NOTIME不设置缓存的保存多久,NORMALTIME给定一个缓存的保存时间限制//3.第一次获取数据从网络中获取,之后缓存数据到我们的本地中之后直接从本地拿到数据即可//4.缓存的过程中涉及到读取和写入的操作

**

package history.six.com.rushingdemo.base;import android.text.TextUtils;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.util.HashMap;import java.util.Set;import history.six.com.rushingdemo.application.MyApplication;import history.six.com.rushingdemo.manager.HttpMangerUtils;import history.six.com.rushingdemo.utils.CommonUtils;import history.six.com.rushingdemo.utils.Md5;import history.six.com.rushingdemo.utils.ToastUtil;import history.six.com.rushingdemo.view.ShowingPager;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response;public abstract class BaseData {    private final File fileDir;    public static final int NOTIME = 0;    public static final int NORMALTIME = 3 * 24 * 60 * 60 * 1000;   //1.网络缓存数据存放的路径    //2.NOTIME不设置缓存的保存多久,NORMALTIME给定一个缓存的保存时间限制    //3.第一次获取数据从网络中获取,之后缓存数据到我们的本地中之后直接从本地拿到数据即可    //4.缓存的过程中涉及到读取和写入的操作    //缓存数据存到哪里?    public BaseData() {        //找到存储路径        File cacheDir = MyApplication.getContext().getCacheDir();        fileDir = new File(cacheDir, "meiru");        if (!fileDir.exists()) {            //创建文件夹            fileDir.mkdir();        }    }    /**     * @param baseUrl   //基础路径     * @param path      //请求的实体内容     * @param validTime //有效时间     */    public void getData(String baseUrl, String path, int validTime) {        //先判断有效时间        if (validTime == 0) {            //直接请求网络,要最新数据            getDataFromNet(baseUrl, path, validTime);        } else {            //从本地获取            String data =  getDataFromLocal(path, validTime);            if (TextUtils.isEmpty(data)) {                //如果为空,请求网络                getDataFromNet(baseUrl, path, validTime);            } else {                //拿到了数据,返回数据                setResultData(data);            }        }    }    /**     * 从网络获取数据     *     * @param path     * @param validTime     */    private void getDataFromNet(String baseUrl, final String path, final int validTime) {        HttpMangerUtils.getData(baseUrl, path, new Callback<String>() {            @Override            public void onResponse(Call<String> call, final Response<String> response) {                CommonUtils.runOnUIThread(new Runnable() {                    @Override                    public void run() {                        //将数据抽象出去                        setResultData(response.body());                    }                });                //将数据写入本地缓存                writeDataToLocal(path, validTime, response.body());            }            @Override            public void onFailure(Call<String> call, Throwable t) {                ToastUtil.show(MyApplication.getContext(), "请求出错,代码" + t.getMessage());                setResulttError(ShowingPager.STATE_LOAD_ERROR);            }        });    }    /**     * @param isReadCookie 判断是否读取Cookie     * @param isSaveCookie 判断是否保存Cookie     * @param baseUrl      设置基础url     * @param path         标准url     * @param argsMap      请求参数实体内容     * @param validTime    设置超时时间     */    public void postData(boolean isReadCookie, boolean isSaveCookie, String baseUrl, String path, HashMap<String, String> argsMap, int validTime) {        Set<String> strings = argsMap.keySet();        StringBuilder stringBuilder = new StringBuilder();        for (String key : strings) {            stringBuilder.append(key).append(argsMap.get(key));        }        //先判断有效时间        if (validTime == 0) {            //直接请求网络,要最新数据            postDataFromNet(isReadCookie, isSaveCookie, baseUrl, path, stringBuilder.toString(), argsMap, validTime);        } else {            //从本地获取            String data = getDataFromLocal(baseUrl + path + stringBuilder.toString(), validTime);            if (TextUtils.isEmpty(data)) {                //如果为空,请求网络                postDataFromNet(isReadCookie, isSaveCookie, baseUrl, path, stringBuilder.toString(), argsMap, validTime);            } else {                //拿到了数据,返回数据                setResultData(data);            }        }    }    /**     * @param isReadCookie 判断是否读取Cookie     * @param isSaveCookie 判断是否保存Cookie     * @param baseUrl      设置基础url     * @param path         标准url     * @param keyValues    请求数据的参数key+values     * @param argsMap      请求参数实体内容     * @param validTime    设置超时时间     */    private void postDataFromNet(boolean isReadCookie, boolean isSaveCookie, final String baseUrl, final String path, final String keyValues, final HashMap<String, String> argsMap, final int validTime) {        HttpMangerUtils.postMethod(isReadCookie, isSaveCookie, baseUrl, path, argsMap, new Callback<String>() {            @Override            public void onResponse(Call<String> call, final Response<String> response) {                CommonUtils.runOnUIThread(new Runnable() {                    @Override                    public void run() {                        //将数据抽象出去                        setResultData(response.body());                    }                });                //将数据写入本地                writeDataToLocal(baseUrl + path + keyValues, validTime, response.body());            }            @Override            public void onFailure(Call<String> call, Throwable t) {                ToastUtil.show(MyApplication.getContext(), "请求出错,代码" + t.getMessage());                setResulttError(ShowingPager.STATE_LOAD_ERROR);            }        });    }    private String getDataFromLocal(String path, int validTime) {        //读取文件信息        //读时间        try {            File file = new File(fileDir, Md5.Md5(path));            BufferedReader bufferedReader = new BufferedReader(new FileReader(file));            String s = bufferedReader.readLine();            long time = Long.parseLong(s);            //和当前时间进行比较            //111-110            if (System.currentTimeMillis() < time) {                //将信息读出来                StringBuilder builder = new StringBuilder();                String line = null;                while ((line = bufferedReader.readLine()) != null) {                    builder.append(line);                }                bufferedReader.close();                return builder.toString();            } else {                //无效                return null;            }        } catch (Exception e) {            e.printStackTrace();        }        return null;    }    public abstract void setResultData(String data);    public abstract void setResulttError(int state);    /**     * 将数据写到本地     *     * @param path     * @param     * @param validTime     * @param     */    private void writeDataToLocal(String path, int validTime, String data) {        //每一条请求,都是生成一个文件   dawedfakwehfaowehfoaw        try {            File file = new File(fileDir, Md5.Md5(path));            //写流信息            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));            bufferedWriter.write(System.currentTimeMillis() + validTime + "\r\n");            //从网络上请求的数据            bufferedWriter.write(data);            bufferedWriter.close();        } catch (Exception e) {            e.printStackTrace();        }    }}

BaseFragment

package history.six.com.rushingdemo.base;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import history.six.com.rushingdemo.interfaces.IResetShowingPageListener;import history.six.com.rushingdemo.utils.NetUtils;import history.six.com.rushingdemo.view.ShowingPager;public abstract class BaseFragment extends Fragment {    public ShowingPager showingPager;    //底部标签Fragment的父类,学会设定抽象方法    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        showingPager = new ShowingPager(getActivity()) {            @Override            public View setSuccessView() {                return setBaseSuccessView();            }            @Override            public void setTitleView(View titleView) {                setBaseTitleView(titleView);            }            @Override            public boolean needTitleView() {                return isNeedTitle();            }        };        return showingPager;    }    @Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        showingPager.setIResetShowingPageListener(new IResetShowingPageListener() {            @Override            public void onResetClick(View view) {                onLoad();            }        });        onLoad();    }    public abstract void onLoad();    public abstract View setBaseSuccessView();    protected abstract boolean isNeedTitle();    public abstract void setBaseTitleView(View v);}

FragmentFactory

package history.six.com.rushingdemo.factory;import android.support.v4.app.Fragment;import java.util.HashMap;import history.six.com.rushingdemo.fragment.CateGoryFragment;import history.six.com.rushingdemo.fragment.DuoBaoFragment;import history.six.com.rushingdemo.fragment.MineFragment;import history.six.com.rushingdemo.fragment.NewJieXiaoFragment;import history.six.com.rushingdemo.fragment.OrderFragment;public class FragmentFactory {    //Fragment的管理类,运用工厂模式    //创建集合    private static HashMap<String, Fragment> fragmentHashMap = new HashMap<>();    //创建静态方法    public static Fragment getFragment(String title) {        Fragment fragment = fragmentHashMap.get(title);        if (fragment != null) {            return fragment;        }        switch (title){            case "夺宝":                fragment = new DuoBaoFragment();                break;            case "分类":                fragment = new CateGoryFragment();                break;            case "最新揭晓":                fragment = new NewJieXiaoFragment();                break;            case "订单":                fragment = new OrderFragment();                break;            case "我的":                fragment = new MineFragment();                break;        }        fragmentHashMap.put(title, fragment);        return fragment;    }}

5个底部标签Fragment都继承BaseFragment ,除了“我的界面”没有网络加载判断不用外,继承Fragment

package history.six.com.rushingdemo.fragment;import android.graphics.Color;import android.support.v7.widget.RecyclerView;import android.view.View;import android.widget.TextView;import android.widget.Toast;import com.youth.banner.Banner;import history.six.com.rushingdemo.R;import history.six.com.rushingdemo.base.BaseData;import history.six.com.rushingdemo.base.BaseFragment;import history.six.com.rushingdemo.interfaces.IResetShowingPageListener;import history.six.com.rushingdemo.view.ShowingPager;public class DuoBaoFragment extends BaseFragment {    private Banner banner;    private RecyclerView mDuoBaoRecyclerView;    /**     * 加载成功视图     * @return     */    @Override    public View setBaseSuccessView() {        View duobao_fragment = View.inflate(getActivity(), R.layout.duobao_fragment,null);        banner = (Banner) duobao_fragment.findViewById(R.id.banner);        mDuoBaoRecyclerView = (RecyclerView) duobao_fragment.findViewById(R.id.duoBaoRecyclerView);        return duobao_fragment;    }    /**     * 设置标题是否需要隐藏     * @return     */    @Override    protected boolean isNeedTitle() {        return true;    }    /**     * 设置标题     * @param v     */    @Override    public void setBaseTitleView(View v) {        TextView middleTitle_tv = (TextView) v.findViewById(R.id.middleTitle_tv);        middleTitle_tv.setText("夺宝");        middleTitle_tv.setTextSize(20);        middleTitle_tv.setTextColor(Color.WHITE);    }    /**     * 加载数据     */    @Override    public void onLoad() {        showingPager.setIResetShowingPageListener(new IResetShowingPageListener() {            @Override            public void onResetClick(View view) {                Toast.makeText(getActivity(), "点击重新加载", Toast.LENGTH_SHORT).show();            }        });        new BaseData() {            @Override            public void setResultData(String data) {                showingPager.setCurrentState(ShowingPager.StateType.STATE_LOAD_SUCCESS);            }            @Override            public void setResulttError(int state) {                showingPager.setCurrentState(ShowingPager.StateType.STATE_LOAD_ERROR);            }        }.getData("www.baidu.com","",BaseData.NOTIME);    }}

接口包

**1. IResetShowingPageListener
2. ReadCookiesInterceptor
3. RetrofitAPI
4. SaveCookiesInterceptor**

IResetShowingPageListener##

package history.six.com.rushingdemo.interfaces;import android.view.View;public interface IResetShowingPageListener {   public void onResetClick(View view);}

ReadCookiesInterceptor

package history.six.com.rushingdemo.interfaces;import java.io.IOException;import history.six.com.rushingdemo.utils.CommonUtils;import okhttp3.Interceptor;import okhttp3.Request;public class ReadCookiesInterceptor implements Interceptor {    @Override    public okhttp3.Response intercept(Chain chain) throws IOException {        Request.Builder builder = chain.request().newBuilder();        String cookie = CommonUtils.getString("cookie");        //将cookie添加到请求头中        builder.addHeader("Cookie", cookie);        return chain.proceed(builder.build());    }}

RetrofitAPI

package history.six.com.rushingdemo.interfaces;import java.util.Map;import retrofit2.Call;import retrofit2.http.FieldMap;import retrofit2.http.FormUrlEncoded;import retrofit2.http.GET;import retrofit2.http.POST;import retrofit2.http.Url;public interface RetrofitAPI {    @GET    Call<String> getMethod(@Url String url);    @FormUrlEncoded    @POST    Call<String> postMothod(@Url String url, @FieldMap Map<String, String> map);}

SaveCookiesInterceptor

package history.six.com.rushingdemo.interfaces;import android.util.Log;import java.io.IOException;import history.six.com.rushingdemo.utils.CommonUtils;import okhttp3.Interceptor;import okhttp3.Response;public class SaveCookiesInterceptor implements Interceptor {    @Override    public Response intercept(Chain chain) throws IOException {        Response originalResponse = chain.proceed(chain.request());        //PHPSESSID=vg6d8mpgmqgni6ct15skcjjm71;loginname=15330276178;        StringBuilder stringBuilder=new StringBuilder();        if (!originalResponse.headers("Set-Cookie").isEmpty()) {            for (String header : originalResponse.headers("Set-Cookie")) {                Log.i("AAAA----","=="+header+"==");                String cookie = header.substring(0, header.indexOf(";") + 1);                stringBuilder.append(cookie);            }        }        Log.i("AAAA","++"+stringBuilder.toString()+"++");        CommonUtils.saveString("cookie",stringBuilder.toString());        return originalResponse;    }}

manager包

HttpMangerUtils

package history.six.com.rushingdemo.manager;import android.util.Log;import java.util.Map;import java.util.concurrent.TimeUnit;import history.six.com.rushingdemo.interfaces.ReadCookiesInterceptor;import history.six.com.rushingdemo.interfaces.RetrofitAPI;import history.six.com.rushingdemo.interfaces.SaveCookiesInterceptor;import okhttp3.OkHttpClient;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response;import retrofit2.Retrofit;import retrofit2.converter.scalars.ScalarsConverterFactory;public class HttpMangerUtils {    private static final int DEFAULT_TIMEOUT = 5;    /**     * get请求方式     *     * @param baseUrl     * @param url     * @param callback     */    public static void getData(String baseUrl, String url, final Callback<String> callback) {        OkHttpClient client = new OkHttpClient.Builder()                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                .build();        Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(ScalarsConverterFactory.create()).client(client).build();        RetrofitAPI projectAPI = retrofit.create(RetrofitAPI.class);        Call<String> call = projectAPI.getMethod(url);        call.enqueue(new Callback<String>() {            @Override            public void onResponse(Call<String> call, Response<String> response) {                callback.onResponse(call, response);            }            @Override            public void onFailure(Call<String> call, Throwable t) {                callback.onFailure(call, t);            }        });    }    /**     * post请求方式     *     * @param baseUrl     * @param url     * @param map     * @param callback     */    public static void postMethod(boolean isReadCookie, boolean isSaveCookie, String baseUrl, String url, Map<String, String> map, final Callback<String> callback) {        OkHttpClient httpClient = null;        if (isReadCookie && !isSaveCookie) {            httpClient = new OkHttpClient.Builder()                    .addInterceptor(new ReadCookiesInterceptor()).connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .build();            Log.i("AAA", "只读不写");        }        if (isSaveCookie && !isReadCookie) {            httpClient = new OkHttpClient.Builder()                    .addInterceptor(new SaveCookiesInterceptor()).connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .build();            Log.i("AAA", "只写不读");        }        if (isSaveCookie && isReadCookie) {            httpClient = new OkHttpClient.Builder().connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .addInterceptor(new SaveCookiesInterceptor()).addInterceptor(new ReadCookiesInterceptor())                    .build();            Log.i("AAA", "有些有毒");        }        if (!isSaveCookie && !isReadCookie) {            httpClient = new OkHttpClient.Builder().connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)                    .build();            Log.i("AAA", "不写不读");        }        Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl).client(httpClient).addConverterFactory(ScalarsConverterFactory.create()).build();        RetrofitAPI projectAPI = retrofit.create(RetrofitAPI.class);        Call<String> call = projectAPI.postMothod(url, map);        call.enqueue(new Callback<String>() {            @Override            public void onResponse(Call<String> call, Response<String> response) {                callback.onResponse(call, response);            }            @Override            public void onFailure(Call<String> call, Throwable t) {                callback.onFailure(call, t);            }        });    }}

BannerImageLoader

package history.six.com.rushingdemo.utils;import android.content.Context;import android.widget.ImageView;import com.bumptech.glide.Glide;import com.youth.banner.loader.ImageLoader;public class BannerImageLoader extends ImageLoader {    @Override    public void displayImage(Context context, Object path, ImageView imageView) {        Glide.with(context).load(path).into(imageView);    }}

CommonUtils

package history.six.com.rushingdemo.utils;import android.content.SharedPreferences;import android.graphics.drawable.Drawable;import android.view.View;import history.six.com.rushingdemo.application.MyApplication;public class CommonUtils {    public static final String TAG = "NEWSTOP";    private static SharedPreferences sharedPreferences;    private static String SP_NAME = "YYDB";    //打气    public static View inflter(int loyoutId) {        View view = View.inflate(MyApplication.getContext(), loyoutId, null);        return view;    }    /**     * dip  相对像素转换为  px绝对像素     *     * @param dip     * @return     */    public static int dip2px(int dip) {        //获取像素密度        float density = MyApplication.getContext().getResources().getDisplayMetrics().density;        //转换        int px = (int) (dip * density + 0.5f);        return px;    }    /**     * px 相对像素转换为  dip 绝对像素     *     * @param px     * @return     */    public static int px2dip(int px) {        //获取像素密度        float density = MyApplication.getContext().getResources().getDisplayMetrics().density;        //转换        int dip = (int) (px / density + 0.5f);        return dip;    }    //获取资源文件中字符串    public static String getString(int stringId) {        String string = MyApplication.getContext().getResources().getString(stringId);        return string;    }    //获取资源文件的drawable文件    public static Drawable getDrawable(int did) {        return MyApplication.getContext().getResources().getDrawable(did);    }    //清空之前保存的titles数据    public static void removeSp(String flag){        if (sharedPreferences == null) {            sharedPreferences = MyApplication.getContext().getSharedPreferences(TAG, MyApplication.getContext().MODE_PRIVATE);        }        SharedPreferences.Editor edit = sharedPreferences.edit();        edit.remove(flag);        edit.commit();    }    //判断当前任务是否在主线程中,如果在主线程中直接执行,否则通过handler执行    public static void runOnUIThread(Runnable runnable) {        if (android.os.Process.myTid() == MyApplication.getMainThreadId()) {            runnable.run();        } else {            MyApplication.getHandler().post(runnable);        }    }    //使用线程池执行runnable    public static void executeRunnable(Runnable runnable) {        MyApplication.getThreadPoll().execute(runnable);    }    public static void saveString(String key, String value) {        if (sharedPreferences == null)            sharedPreferences = MyApplication.getContext().getSharedPreferences(SP_NAME, MyApplication.getContext().MODE_PRIVATE);        sharedPreferences.edit().putString(key, value).commit();    }    //获取String 的 sp    public static String getString(String str) {        if (sharedPreferences == null) {            sharedPreferences = MyApplication.getContext().getSharedPreferences(SP_NAME, MyApplication.getContext().MODE_PRIVATE);        }        return sharedPreferences.getString(str, null);    }    //保存 Boolean 的 sp    public static void saveBolean(String str, boolean flag) {        if (sharedPreferences == null) {            sharedPreferences = MyApplication.getContext().getSharedPreferences(SP_NAME, MyApplication.getContext().MODE_PRIVATE);        }        SharedPreferences.Editor edit = sharedPreferences.edit();        edit.putBoolean(str, flag);        edit.commit();    }    //获取  Boolean的sp    public static boolean getBoolean(String str) {        if (sharedPreferences == null) {            sharedPreferences = MyApplication.getContext().getSharedPreferences(SP_NAME, MyApplication.getContext().MODE_PRIVATE);        }        return sharedPreferences.getBoolean(str, false);    }}

LogUtils

package history.six.com.rushingdemo.utils;import android.util.Log;public class LogUtils {    public static final  boolean isDebug=true;    public static void i(String TAG, String info){        if(isDebug){            Log.i(TAG,info);        }    }    public static void d(String TAG, String info){        if(isDebug){            Log.d(TAG,info);        }    }    public static void e(String TAG, String info){        if(isDebug){            Log.e(TAG,info);        }    }}

Md5

package history.six.com.rushingdemo.utils;import java.security.MessageDigest;public class Md5 {    private static StringBuffer buf;    public static String Md5(String plainText ) {        try {         MessageDigest md = MessageDigest.getInstance("MD5");        md.update(plainText.getBytes());         byte b[] = md.digest();         int i;         buf = new StringBuffer("");        for (int offset = 0; offset < b.length; offset++) {         i = b[offset];         if(i<0) i+= 256;         if(i<16)         buf.append("0");         buf.append(Integer.toHexString(i));        }         //System.out.println("result: " + buf.toString());//32位的加密         //System.out.println("result: " + buf.toString().substring(8,24));//16位的加密         } catch (Exception e) {        // TODO Auto-generated catch block         e.printStackTrace();         }             return buf.toString();        } }

MyGlideMode

package history.six.com.rushingdemo.utils;import android.content.Context;import android.os.Environment;import com.bumptech.glide.Glide;import com.bumptech.glide.GlideBuilder;import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory;import com.bumptech.glide.load.engine.cache.LruResourceCache;import com.bumptech.glide.module.GlideModule;import java.io.File;public class MyGlideMode implements GlideModule {    /**使用方法     * Glide.with(WaterWallActivity.this)        .load(加载路径)        .placeholder(默认加载)        .error(加载错误)        .into(控件);     * @param context     * @param builder     */    @Override    public void applyOptions(Context context, GlideBuilder builder) {        int maxMemory = (int) Runtime.getRuntime().maxMemory();//获取系统分配给应用的总内存大小        int memoryCacheSize = maxMemory / 8;//设置图片内存缓存占用八分之一        //设置内存缓存大小        builder.setMemoryCache(new LruResourceCache(memoryCacheSize));        //指定到SDcard        File cacheDir = Environment.getExternalStorageDirectory();//指定的是数据的缓存地址        int diskCacheSize = 1024 * 1024 * 30;//最多可以缓存多少字节的数据        //设置磁盘缓存大小        builder.setDiskCache(new DiskLruCacheFactory(cacheDir.getPath(), "glide", diskCacheSize));    }    @Override    public void registerComponents(Context context, Glide glide) {    }}

NetUtils

package history.six.com.rushingdemo.utils;import android.content.Context;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.telephony.TelephonyManager;import android.text.TextUtils;import history.six.com.rushingdemo.application.MyApplication;public class NetUtils {    public static boolean isHaveNet() {        if (getNetWorkType(MyApplication.getContext()) == NETWORKTYPE_INVALID) {            return false;        } else {            return true;        }    }    /**     * 没有网络     */    public static final int NETWORKTYPE_INVALID = 0;    /**     * wap网络     */    public static final int NETWORKTYPE_WAP = 1;    /**     * 2G网络     */    public static final int NETWORKTYPE_2G = 2;    /**     * 3G和3G以上网络,或统称为快速网络     */    public static final int NETWORKTYPE_3G = 3;    /**     * wifi网络     */    public static final int NETWORKTYPE_WIFI = 4;    private static int mNetWorkType;    /**     * LogUtils.java     * 获取网络状态,wifi,wap,2g,3g.     *     * @param context 上下文     * @return int 网络状态 {@link #NETWORKTYPE_2G},{@link #NETWORKTYPE_3G}, *     * {@link #NETWORKTYPE_INVALID},{@link #NETWORKTYPE_WAP}*     * <p>     * {@link #NETWORKTYPE_WIFI}     */    public static boolean isFastMobileNetwork(Context context) {        TelephonyManager telephonyManager = (TelephonyManager) context                .getSystemService(Context.TELEPHONY_SERVICE);        switch (telephonyManager.getNetworkType()) {            case TelephonyManager.NETWORK_TYPE_1xRTT:                return false; // ~ 50-100 kbps            case TelephonyManager.NETWORK_TYPE_CDMA:                return false; // ~ 14-64 kbps            case TelephonyManager.NETWORK_TYPE_EDGE:                return false; // ~ 50-100 kbps            case TelephonyManager.NETWORK_TYPE_EVDO_0:                return true; // ~ 400-1000 kbps            case TelephonyManager.NETWORK_TYPE_EVDO_A:                return true; // ~ 600-1400 kbps            case TelephonyManager.NETWORK_TYPE_GPRS:                return false; // ~ 100 kbps            case TelephonyManager.NETWORK_TYPE_HSDPA:                return true; // ~ 2-14 Mbps            case TelephonyManager.NETWORK_TYPE_HSPA:                return true; // ~ 700-1700 kbps            case TelephonyManager.NETWORK_TYPE_HSUPA:                return true; // ~ 1-23 Mbps            case TelephonyManager.NETWORK_TYPE_UMTS:                return true; // ~ 400-7000 kbps            case TelephonyManager.NETWORK_TYPE_EHRPD:                return true; // ~ 1-2 Mbps            case TelephonyManager.NETWORK_TYPE_EVDO_B:                return true; // ~ 5 Mbps            case TelephonyManager.NETWORK_TYPE_HSPAP:                return true; // ~ 10-20 Mbps            case TelephonyManager.NETWORK_TYPE_IDEN:                return false; // ~25 kbps            case TelephonyManager.NETWORK_TYPE_LTE:                return true; // ~ 10+ Mbps            case TelephonyManager.NETWORK_TYPE_UNKNOWN:                return false;            default:                return false;        }    }    public static int getNetWorkType(Context context) {        String str = null;        ConnectivityManager manager = (ConnectivityManager) context                .getSystemService(Context.CONNECTIVITY_SERVICE);        NetworkInfo networkInfo = manager.getActiveNetworkInfo();        if (networkInfo != null && networkInfo.isConnected()) {            String type = networkInfo.getTypeName();            if (type.equalsIgnoreCase("WIFI")) {                mNetWorkType = NETWORKTYPE_WIFI;            } else if (type.equalsIgnoreCase("MOBILE")) {                String proxyHost = android.net.Proxy.getDefaultHost();                mNetWorkType = TextUtils.isEmpty(proxyHost) ? (isFastMobileNetwork(context) ? NETWORKTYPE_3G                        : NETWORKTYPE_2G)                        : NETWORKTYPE_WAP;            }        } else {            mNetWorkType = NETWORKTYPE_INVALID;        }        return mNetWorkType;    }}

PermissionUtils

package history.six.com.rushingdemo.utils;import android.annotation.TargetApi;import android.app.Activity;import android.content.Context;import android.content.pm.PackageManager;import android.os.Build;import android.support.v4.content.ContextCompat;import java.util.ArrayList;import java.util.List;public class PermissionUtils {    //权限工具类    private static int mRequestCode = -1;    private static OnPermissionListener mOnPermissionListener;    public interface OnPermissionListener {        void onPermissionGranted();        void onPermissionDenied();    }    @TargetApi(Build.VERSION_CODES.M)    public static void requestPermissions(Context context, int requestCode            , String[] permissions, OnPermissionListener listener) {        if (context instanceof Activity) {            mOnPermissionListener = listener;            List<String> deniedPermissions = getDeniedPermissions(context, permissions);            if (deniedPermissions.size() > 0) {                mRequestCode = requestCode;                ((Activity) context).requestPermissions(deniedPermissions                        .toArray(new String[deniedPermissions.size()]), requestCode);            } else {                if (mOnPermissionListener != null)                    mOnPermissionListener.onPermissionGranted();            }        } else {            throw new RuntimeException("Context must be an Activity");        }    }    /**     * 获取请求权限中需要授权的权限     */    private static List<String> getDeniedPermissions(Context context, String... permissions) {        List<String> deniedPermissions = new ArrayList<>();        for (String permission : permissions) {            if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED) {                deniedPermissions.add(permission);            }        }        return deniedPermissions;    }    /**     * 请求权限结果,对应Activity中onRequestPermissionsResult()方法。     */    public static void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {        if (mRequestCode != -1 && requestCode == mRequestCode) {            if (mOnPermissionListener != null) {                if (verifyPermissions(grantResults)) {                    mOnPermissionListener.onPermissionGranted();                } else {                    mOnPermissionListener.onPermissionDenied();                }            }        }    }    /**     * 验证所有权限是否都已经授权     */    private static boolean verifyPermissions(int[] grantResults) {        for (int grantResult : grantResults) {            if (grantResult != PackageManager.PERMISSION_GRANTED) {                return false;            }        }        return true;    }}

ToastUtil

package history.six.com.rushingdemo.utils;import android.content.Context;import android.widget.Toast;public class ToastUtil {    public static void show(Context context, String content) {        Toast.makeText(context, content, Toast.LENGTH_SHORT).show();    }    public static void showLong(Context context, int contentId) {        Toast.makeText(context, contentId, Toast.LENGTH_LONG).show();    }}

view包

LazyViewPager

package history.six.com.rushingdemo.view;//viewpage禁止预加载父类/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */import android.content.Context;import android.database.DataSetObserver;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.os.Parcel;import android.os.Parcelable;import android.os.SystemClock;import android.support.v4.os.ParcelableCompat;import android.support.v4.os.ParcelableCompatCreatorCallbacks;import android.support.v4.view.KeyEventCompat;import android.support.v4.view.MotionEventCompat;import android.support.v4.view.PagerAdapter;import android.support.v4.view.VelocityTrackerCompat;import android.support.v4.view.ViewCompat;import android.support.v4.view.ViewConfigurationCompat;import android.support.v4.widget.EdgeEffectCompat;import android.util.AttributeSet;import android.util.Log;import android.view.FocusFinder;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.SoundEffectConstants;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.view.ViewParent;import android.view.accessibility.AccessibilityEvent;import android.view.animation.Interpolator;import android.widget.Scroller;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;/** * Layout manager that allows the user to flip left and right * through pages of data.  You supply an implementation of a * {@link PagerAdapter} to generate the pages that the view shows. * <p> * <p>Note this class is currently under early design and * development.  The API will likely change in later updates of * the compatibility library, requiring changes to the source code * of apps when they are compiled against the newer version.</p> */public class LazyViewPager extends ViewGroup {    private static final String TAG = "LazyViewPager";    private static final boolean DEBUG = false;    private static final boolean USE_CACHE = false;    //设置默认加载的页数,可以灵活进行设置    private static final int DEFAULT_OFFSCREEN_PAGES = 0;    private static final int MAX_SETTLE_DURATION = 600;    static class ItemInfo {        Object object;        int position;        boolean scrolling;    }    private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>() {        @Override        public int compare(ItemInfo lhs, ItemInfo rhs) {            return lhs.position - rhs.position;        }    };    private static final Interpolator sInterpolator = new Interpolator() {        public float getInterpolation(float t) {            // _o(t) = t * t * ((tension + 1) * t + tension)            // o(t) = _o(t - 1) + 1            t -= 1.0f;            return t * t * t + 1.0f;        }    };    private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();    private PagerAdapter mAdapter;    private int mCurItem;   // Index of currently displayed page.    private int mRestoredCurItem = -1;    private Parcelable mRestoredAdapterState = null;    private ClassLoader mRestoredClassLoader = null;    private Scroller mScroller;    private PagerObserver mObserver;    private int mPageMargin;    private Drawable mMarginDrawable;    private int mChildWidthMeasureSpec;    private int mChildHeightMeasureSpec;    private boolean mInLayout;    private boolean mScrollingCacheEnabled;    private boolean mPopulatePending;    private boolean mScrolling;    private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;    private boolean mIsBeingDragged;    private boolean mIsUnableToDrag;    private int mTouchSlop;    private float mInitialMotionX;    /**     * Position of the last motion event.     */    private float mLastMotionX;    private float mLastMotionY;    /**     * ID of the active pointer. This is used to retain consistency during     * drags/flings if multiple pointers are used.     */    private int mActivePointerId = INVALID_POINTER;    /**     * Sentinel value for no current active pointer.     * Used by {@link #mActivePointerId}.     */    private static final int INVALID_POINTER = -1;    /**     * Determines speed during touch scrolling     */    private VelocityTracker mVelocityTracker;    private int mMinimumVelocity;    private int mMaximumVelocity;    private float mBaseLineFlingVelocity;    private float mFlingVelocityInfluence;    private boolean mFakeDragging;    private long mFakeDragBeginTime;    private EdgeEffectCompat mLeftEdge;    private EdgeEffectCompat mRightEdge;    private boolean mFirstLayout = true;    private OnPageChangeListener mOnPageChangeListener;    /**     * Indicates that the pager is in an idle, settled state. The current page     * is fully in view and no animation is in progress.     */    public static final int SCROLL_STATE_IDLE = 0;    /**     * Indicates that the pager is currently being dragged by the user.     */    public static final int SCROLL_STATE_DRAGGING = 1;    /**     * Indicates that the pager is in the process of settling to a final position.     */    public static final int SCROLL_STATE_SETTLING = 2;    private int mScrollState = SCROLL_STATE_IDLE;    /**     * Callback interface for responding to changing state of the selected page.     */    public interface OnPageChangeListener {        /**         * This method will be invoked when the current page is scrolled, either as part         * of a programmatically initiated smooth scroll or a user initiated touch scroll.         *         * @param position             Position index of the first page currently being displayed.         *                             Page position+1 will be visible if positionOffset is nonzero.         * @param positionOffset       Value from [0, 1) indicating the offset from the page at position.         * @param positionOffsetPixels Value in pixels indicating the offset from position.         */        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);        /**         * This method will be invoked when a new page becomes selected. Animation is not         * necessarily complete.         *         * @param position Position index of the new selected page.         */        public void onPageSelected(int position);        /**         * Called when the scroll state changes. Useful for discovering when the user         * begins dragging, when the pager is automatically settling to the current page,         * or when it is fully stopped/idle.         *         * @param state The new scroll state.         * @see android.support.v4.view.ViewPager#SCROLL_STATE_IDLE         * @see android.support.v4.view.ViewPager#SCROLL_STATE_DRAGGING         * @see android.support.v4.view.ViewPager#SCROLL_STATE_SETTLING         */        public void onPageScrollStateChanged(int state);    }    public static class SimpleOnPageChangeListener implements OnPageChangeListener {        @Override        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            // This space for rent        }        @Override        public void onPageSelected(int position) {            // This space for rent        }        @Override        public void onPageScrollStateChanged(int state) {            // This space for rent        }    }    public LazyViewPager(Context context) {        super(context);        initViewPager();    }    public LazyViewPager(Context context, AttributeSet attrs) {        super(context, attrs);        initViewPager();    }    void initViewPager() {        setWillNotDraw(false);        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);        setFocusable(true);        final Context context = getContext();        mScroller = new Scroller(context, sInterpolator);        final ViewConfiguration configuration = ViewConfiguration.get(context);        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();        mLeftEdge = new EdgeEffectCompat(context);        mRightEdge = new EdgeEffectCompat(context);        float density = context.getResources().getDisplayMetrics().density;        mBaseLineFlingVelocity = 2500.0f * density;        mFlingVelocityInfluence = 0.4f;    }    private void setScrollState(int newState) {        if (mScrollState == newState) {            return;        }        mScrollState = newState;        if (mOnPageChangeListener != null) {            mOnPageChangeListener.onPageScrollStateChanged(newState);        }    }    public void setAdapter(PagerAdapter adapter) {        if (mAdapter != null) {//            mAdapter.unregisterDataSetObserver(mObserver);            mAdapter.startUpdate(this);            for (int i = 0; i < mItems.size(); i++) {                final ItemInfo ii = mItems.get(i);                mAdapter.destroyItem(this, ii.position, ii.object);            }            mAdapter.finishUpdate(this);            mItems.clear();            removeAllViews();            mCurItem = 0;            scrollTo(0, 0);        }        mAdapter = adapter;        if (mAdapter != null) {            if (mObserver == null) {                mObserver = new PagerObserver();            }//            mAdapter.registerDataSetObserver(mObserver);            mPopulatePending = false;            if (mRestoredCurItem >= 0) {                mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);                setCurrentItemInternal(mRestoredCurItem, false, true);                mRestoredCurItem = -1;                mRestoredAdapterState = null;                mRestoredClassLoader = null;            } else {                populate();            }        }    }    public PagerAdapter getAdapter() {        return mAdapter;    }    /**     * Set the currently selected page. If the ViewPager has already been through its first     * layout there will be a smooth animated transition between the current item and the     * specified item.     *     * @param item Item index to select     */    public void setCurrentItem(int item) {        mPopulatePending = false;        setCurrentItemInternal(item, !mFirstLayout, false);    }    /**     * Set the currently selected page.     *     * @param item         Item index to select     * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately     */    public void setCurrentItem(int item, boolean smoothScroll) {        mPopulatePending = false;        setCurrentItemInternal(item, smoothScroll, false);    }    public int getCurrentItem() {        return mCurItem;    }    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {        setCurrentItemInternal(item, smoothScroll, always, 0);    }    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {        if (mAdapter == null || mAdapter.getCount() <= 0) {            setScrollingCacheEnabled(false);            return;        }        if (!always && mCurItem == item && mItems.size() != 0) {            setScrollingCacheEnabled(false);            return;        }        if (item < 0) {            item = 0;        } else if (item >= mAdapter.getCount()) {            item = mAdapter.getCount() - 1;        }        final int pageLimit = mOffscreenPageLimit;        if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) {            // We are doing a jump by more than one page.  To avoid            // glitches, we want to keep all current pages in the view            // until the scroll ends.            for (int i = 0; i < mItems.size(); i++) {                mItems.get(i).scrolling = true;            }        }        final boolean dispatchSelected = mCurItem != item;        mCurItem = item;        populate();        final int destX = (getWidth() + mPageMargin) * item;        if (smoothScroll) {            smoothScrollTo(destX, 0, velocity);            if (dispatchSelected && mOnPageChangeListener != null) {                mOnPageChangeListener.onPageSelected(item);            }        } else {            if (dispatchSelected && mOnPageChangeListener != null) {                mOnPageChangeListener.onPageSelected(item);            }            completeScroll();            scrollTo(destX, 0);        }    }    public void setOnPageChangeListener(OnPageChangeListener listener) {        mOnPageChangeListener = listener;    }    /**     * Returns the number of pages that will be retained to either side of the     * current page in the view hierarchy in an idle state. Defaults to 1.     *     * @return How many pages will be kept offscreen on either side     * @see #setOffscreenPageLimit(int)     */    public int getOffscreenPageLimit() {        return mOffscreenPageLimit;    }    /**     * Set the number of pages that should be retained to either side of the     * current page in the view hierarchy in an idle state. Pages beyond this     * limit will be recreated from the adapter when needed.     * <p>     * <p>This is offered as an optimization. If you know in advance the number     * of pages you will need to support or have lazy-loading mechanisms in place     * on your pages, tweaking this setting can have benefits in perceived smoothness     * of paging animations and interaction. If you have a small number of pages (3-4)     * that you can keep active all at once, less time will be spent in layout for     * newly created view subtrees as the user pages back and forth.</p>     * <p>     * <p>You should keep this limit low, especially if your pages have complex layouts.     * This setting defaults to 1.</p>     *     * @param limit How many pages will be kept offscreen in an idle state.     */    public void setOffscreenPageLimit(int limit) {        if (limit < DEFAULT_OFFSCREEN_PAGES) {            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +                    DEFAULT_OFFSCREEN_PAGES);            limit = DEFAULT_OFFSCREEN_PAGES;        }        if (limit != mOffscreenPageLimit) {            mOffscreenPageLimit = limit;            populate();        }    }    /**     * Set the margin between pages.     *     * @param marginPixels Distance between adjacent pages in pixels     * @see #getPageMargin()     * @see #setPageMarginDrawable(Drawable)     * @see #setPageMarginDrawable(int)     */    public void setPageMargin(int marginPixels) {        final int oldMargin = mPageMargin;        mPageMargin = marginPixels;        final int width = getWidth();        recomputeScrollPosition(width, width, marginPixels, oldMargin);        requestLayout();    }    /**     * Return the margin between pages.     *     * @return The size of the margin in pixels     */    public int getPageMargin() {        return mPageMargin;    }    /**     * Set a drawable that will be used to fill the margin between pages.     *     * @param d Drawable to display between pages     */    public void setPageMarginDrawable(Drawable d) {        mMarginDrawable = d;        if (d != null) refreshDrawableState();        setWillNotDraw(d == null);        invalidate();    }    /**     * Set a drawable that will be used to fill the margin between pages.     *     * @param resId Resource ID of a drawable to display between pages     */    public void setPageMarginDrawable(int resId) {        setPageMarginDrawable(getContext().getResources().getDrawable(resId));    }    @Override    protected boolean verifyDrawable(Drawable who) {        return super.verifyDrawable(who) || who == mMarginDrawable;    }    @Override    protected void drawableStateChanged() {        super.drawableStateChanged();        final Drawable d = mMarginDrawable;        if (d != null && d.isStateful()) {            d.setState(getDrawableState());        }    }    // We want the duration of the page snap animation to be influenced by the distance that    // the screen has to travel, however, we don't want this duration to be effected in a    // purely linear fashion. Instead, we use this method to moderate the effect that the distance    // of travel has on the overall snap duration.    float distanceInfluenceForSnapDuration(float f) {        f -= 0.5f; // center the values about 0.        f *= 0.3f * Math.PI / 2.0f;        return (float) Math.sin(f);    }    /**     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.     *     * @param x the number of pixels to scroll by on the X axis     * @param y the number of pixels to scroll by on the Y axis     */    void smoothScrollTo(int x, int y) {        smoothScrollTo(x, y, 0);    }    /**     * Like {@link View#scrollBy}, but scroll smoothly instead of immediately.     *     * @param x        the number of pixels to scroll by on the X axis     * @param y        the number of pixels to scroll by on the Y axis     * @param velocity the velocity associated with a fling, if applicable. (0 otherwise)     */    void smoothScrollTo(int x, int y, int velocity) {        if (getChildCount() == 0) {            // Nothing to do.            setScrollingCacheEnabled(false);            return;        }        int sx = getScrollX();        int sy = getScrollY();        int dx = x - sx;        int dy = y - sy;        if (dx == 0 && dy == 0) {            completeScroll();            setScrollState(SCROLL_STATE_IDLE);            return;        }        setScrollingCacheEnabled(true);        mScrolling = true;        setScrollState(SCROLL_STATE_SETTLING);        final float pageDelta = (float) Math.abs(dx) / (getWidth() + mPageMargin);        int duration = (int) (pageDelta * 100);        velocity = Math.abs(velocity);        if (velocity > 0) {            duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence;        } else {            duration += 100;        }        duration = Math.min(duration, MAX_SETTLE_DURATION);        mScroller.startScroll(sx, sy, dx, dy, duration);        invalidate();    }    void addNewItem(int position, int index) {        ItemInfo ii = new ItemInfo();        ii.position = position;        ii.object = mAdapter.instantiateItem(this, position);        if (index < 0) {            mItems.add(ii);        } else {            mItems.add(index, ii);        }    }    void dataSetChanged() {        // This method only gets called if our observer is attached, so mAdapter is non-null.        boolean needPopulate = mItems.size() < 3 && mItems.size() < mAdapter.getCount();        int newCurrItem = -1;        for (int i = 0; i < mItems.size(); i++) {            final ItemInfo ii = mItems.get(i);            final int newPos = mAdapter.getItemPosition(ii.object);            if (newPos == PagerAdapter.POSITION_UNCHANGED) {                continue;            }            if (newPos == PagerAdapter.POSITION_NONE) {                mItems.remove(i);                i--;                mAdapter.destroyItem(this, ii.position, ii.object);                needPopulate = true;                if (mCurItem == ii.position) {                    // Keep the current item in the valid range                    newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1));                }                continue;            }            if (ii.position != newPos) {                if (ii.position == mCurItem) {                    // Our current item changed position. Follow it.                    newCurrItem = newPos;                }                ii.position = newPos;                needPopulate = true;            }        }        Collections.sort(mItems, COMPARATOR);        if (newCurrItem >= 0) {            // TODO This currently causes a jump.            setCurrentItemInternal(newCurrItem, false, true);            needPopulate = true;        }        if (needPopulate) {            populate();            requestLayout();        }    }    void populate() {        if (mAdapter == null) {            return;        }        // Bail now if we are waiting to populate.  This is to hold off        // on creating views from the time the user releases their finger to        // fling to a new position until we have finished the scroll to        // that position, avoiding glitches from happening at that point.        if (mPopulatePending) {            if (DEBUG) Log.i(TAG, "populate is pending, skipping for now...");            return;        }        // Also, don't populate until we are attached to a window.  This is to        // avoid trying to populate before we have restored our view hierarchy        // state and conflicting with what is restored.        if (getWindowToken() == null) {            return;        }        mAdapter.startUpdate(this);        final int pageLimit = mOffscreenPageLimit;        final int startPos = Math.max(0, mCurItem - pageLimit);        final int N = mAdapter.getCount();        final int endPos = Math.min(N - 1, mCurItem + pageLimit);        if (DEBUG) Log.v(TAG, "populating: startPos=" + startPos + " endPos=" + endPos);        // Add and remove pages in the existing list.        int lastPos = -1;        for (int i = 0; i < mItems.size(); i++) {            ItemInfo ii = mItems.get(i);            if ((ii.position < startPos || ii.position > endPos) && !ii.scrolling) {                if (DEBUG) Log.i(TAG, "removing: " + ii.position + " @ " + i);                mItems.remove(i);                i--;                mAdapter.destroyItem(this, ii.position, ii.object);            } else if (lastPos < endPos && ii.position > startPos) {                // The next item is outside of our range, but we have a gap                // between it and the last item where we want to have a page                // shown.  Fill in the gap.                lastPos++;                if (lastPos < startPos) {                    lastPos = startPos;                }                while (lastPos <= endPos && lastPos < ii.position) {                    if (DEBUG) Log.i(TAG, "inserting: " + lastPos + " @ " + i);                    addNewItem(lastPos, i);                    lastPos++;                    i++;                }            }            lastPos = ii.position;        }        // Add any new pages we need at the end.        lastPos = mItems.size() > 0 ? mItems.get(mItems.size() - 1).position : -1;        if (lastPos < endPos) {            lastPos++;            lastPos = lastPos > startPos ? lastPos : startPos;            while (lastPos <= endPos) {                if (DEBUG) Log.i(TAG, "appending: " + lastPos);                addNewItem(lastPos, -1);                lastPos++;            }        }        if (DEBUG) {            Log.i(TAG, "Current page list:");            for (int i = 0; i < mItems.size(); i++) {                Log.i(TAG, "#" + i + ": page " + mItems.get(i).position);            }        }        ItemInfo curItem = null;        for (int i = 0; i < mItems.size(); i++) {            if (mItems.get(i).position == mCurItem) {                curItem = mItems.get(i);                break;            }        }        mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);        mAdapter.finishUpdate(this);        if (hasFocus()) {            View currentFocused = findFocus();            ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null;            if (ii == null || ii.position != mCurItem) {                for (int i = 0; i < getChildCount(); i++) {                    View child = getChildAt(i);                    ii = infoForChild(child);                    if (ii != null && ii.position == mCurItem) {                        if (child.requestFocus(FOCUS_FORWARD)) {                            break;                        }                    }                }            }        }    }    public static class SavedState extends BaseSavedState {        int position;        Parcelable adapterState;        ClassLoader loader;        public SavedState(Parcelable superState) {            super(superState);        }        @Override        public void writeToParcel(Parcel out, int flags) {            super.writeToParcel(out, flags);            out.writeInt(position);            out.writeParcelable(adapterState, flags);        }        @Override        public String toString() {            return "FragmentPager.SavedState{"                    + Integer.toHexString(System.identityHashCode(this))                    + " position=" + position + "}";        }        public static final Creator<SavedState> CREATOR                = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() {            @Override            public SavedState createFromParcel(Parcel in, ClassLoader loader) {                return new SavedState(in, loader);            }            @Override            public SavedState[] newArray(int size) {                return new SavedState[size];            }        });        SavedState(Parcel in, ClassLoader loader) {            super(in);            if (loader == null) {                loader = getClass().getClassLoader();            }            position = in.readInt();            adapterState = in.readParcelable(loader);            this.loader = loader;        }    }    @Override    public Parcelable onSaveInstanceState() {        Parcelable superState = super.onSaveInstanceState();        SavedState ss = new SavedState(superState);        ss.position = mCurItem;        if (mAdapter != null) {            ss.adapterState = mAdapter.saveState();        }        return ss;    }    @Override    public void onRestoreInstanceState(Parcelable state) {        if (!(state instanceof SavedState)) {            super.onRestoreInstanceState(state);            return;        }        SavedState ss = (SavedState) state;        super.onRestoreInstanceState(ss.getSuperState());        if (mAdapter != null) {            mAdapter.restoreState(ss.adapterState, ss.loader);            setCurrentItemInternal(ss.position, false, true);        } else {            mRestoredCurItem = ss.position;            mRestoredAdapterState = ss.adapterState;            mRestoredClassLoader = ss.loader;        }    }    @Override    public void addView(View child, int index, LayoutParams params) {        if (mInLayout) {            addViewInLayout(child, index, params);            child.measure(mChildWidthMeasureSpec, mChildHeightMeasureSpec);        } else {            super.addView(child, index, params);        }        if (USE_CACHE) {            if (child.getVisibility() != GONE) {                child.setDrawingCacheEnabled(mScrollingCacheEnabled);            } else {                child.setDrawingCacheEnabled(false);            }        }    }    ItemInfo infoForChild(View child) {        for (int i = 0; i < mItems.size(); i++) {            ItemInfo ii = mItems.get(i);            if (mAdapter.isViewFromObject(child, ii.object)) {                return ii;            }        }        return null;    }    ItemInfo infoForAnyChild(View child) {        ViewParent parent;        while ((parent = child.getParent()) != this) {            if (parent == null || !(parent instanceof View)) {                return null;            }            child = (View) parent;        }        return infoForChild(child);    }    @Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        mFirstLayout = true;    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // For simple implementation, or internal size is always 0.        // We depend on the container to specify the layout size of        // our view.  We can't really know what it is since we will be        // adding and removing different arbitrary views and do not        // want the layout to change as this happens.        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec),                getDefaultSize(0, heightMeasureSpec));        // Children are just made to fill our space.        mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -                getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY);        mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -                getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY);        // Make sure we have created all fragments that we need to have shown.        mInLayout = true;        populate();        mInLayout = false;        // Make sure all children have been properly measured.        final int size = getChildCount();        for (int i = 0; i < size; ++i) {            final View child = getChildAt(i);            if (child.getVisibility() != GONE) {                if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child                        + ": " + mChildWidthMeasureSpec);                child.measure(mChildWidthMeasureSpec, mChildHeightMeasureSpec);            }        }    }    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        // Make sure scroll position is set correctly.        if (w != oldw) {            recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin);        }    }    private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) {        final int widthWithMargin = width + margin;        if (oldWidth > 0) {            final int oldScrollPos = getScrollX();            final int oldwwm = oldWidth + oldMargin;            final int oldScrollItem = oldScrollPos / oldwwm;            final float scrollOffset = (float) (oldScrollPos % oldwwm) / oldwwm;            final int scrollPos = (int) ((oldScrollItem + scrollOffset) * widthWithMargin);            scrollTo(scrollPos, getScrollY());            if (!mScroller.isFinished()) {                // We now return to your regularly scheduled scroll, already in progress.                final int newDuration = mScroller.getDuration() - mScroller.timePassed();                mScroller.startScroll(scrollPos, 0, mCurItem * widthWithMargin, 0, newDuration);            }        } else {            int scrollPos = mCurItem * widthWithMargin;            if (scrollPos != getScrollX()) {                completeScroll();                scrollTo(scrollPos, getScrollY());            }        }    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        mInLayout = true;        populate();        mInLayout = false;        final int count = getChildCount();        final int width = r - l;        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            ItemInfo ii;            if (child.getVisibility() != GONE && (ii = infoForChild(child)) != null) {                int loff = (width + mPageMargin) * ii.position;                int childLeft = getPaddingLeft() + loff;                int childTop = getPaddingTop();                if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object                        + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth()                        + "x" + child.getMeasuredHeight());                child.layout(childLeft, childTop,                        childLeft + child.getMeasuredWidth(),                        childTop + child.getMeasuredHeight());            }        }        mFirstLayout = false;    }    @Override    public void computeScroll() {        if (DEBUG) Log.i(TAG, "computeScroll: finished=" + mScroller.isFinished());        if (!mScroller.isFinished()) {            if (mScroller.computeScrollOffset()) {                if (DEBUG) Log.i(TAG, "computeScroll: still scrolling");                int oldX = getScrollX();                int oldY = getScrollY();                int x = mScroller.getCurrX();                int y = mScroller.getCurrY();                if (oldX != x || oldY != y) {                    scrollTo(x, y);                }                if (mOnPageChangeListener != null) {                    final int widthWithMargin = getWidth() + mPageMargin;                    final int position = x / widthWithMargin;                    final int offsetPixels = x % widthWithMargin;                    final float offset = (float) offsetPixels / widthWithMargin;                    mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels);                }                // Keep on drawing until the animation has finished.                invalidate();                return;            }        }        // Done with scroll, clean up state.        completeScroll();    }    private void completeScroll() {        boolean needPopulate = mScrolling;        if (needPopulate) {            // Done with scroll, no longer want to cache view drawing.            setScrollingCacheEnabled(false);            mScroller.abortAnimation();            int oldX = getScrollX();            int oldY = getScrollY();            int x = mScroller.getCurrX();            int y = mScroller.getCurrY();            if (oldX != x || oldY != y) {                scrollTo(x, y);            }            setScrollState(SCROLL_STATE_IDLE);        }        mPopulatePending = false;        mScrolling = false;        for (int i = 0; i < mItems.size(); i++) {            ItemInfo ii = mItems.get(i);            if (ii.scrolling) {                needPopulate = true;                ii.scrolling = false;            }        }        if (needPopulate) {            populate();        }    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        /*         * This method JUST determines whether we want to intercept the motion.         * If we return true, onMotionEvent will be called and we do the actual         * scrolling there.         */        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;        // Always take care of the touch gesture being complete.        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {            // Release the drag.            if (DEBUG) Log.v(TAG, "Intercept done!");            mIsBeingDragged = false;            mIsUnableToDrag = false;            mActivePointerId = INVALID_POINTER;            return false;        }        // Nothing more to do here if we have decided whether or not we        // are dragging.        if (action != MotionEvent.ACTION_DOWN) {            if (mIsBeingDragged) {                if (DEBUG) Log.v(TAG, "Intercept returning true!");                return true;            }            if (mIsUnableToDrag) {                if (DEBUG) Log.v(TAG, "Intercept returning false!");                return false;            }        }        switch (action) {            case MotionEvent.ACTION_MOVE: {                /*                 * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check                 * whether the user has moved far enough from his original down touch.                 */                /*                * Locally do absolute value. mLastMotionY is set to the y value                * of the down event.                */                final int activePointerId = mActivePointerId;                if (activePointerId == INVALID_POINTER) {                    // If we don't have a valid id, the touch down wasn't on content.                    break;                }                final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId);                final float x = MotionEventCompat.getX(ev, pointerIndex);                final float dx = x - mLastMotionX;                final float xDiff = Math.abs(dx);                final float y = MotionEventCompat.getY(ev, pointerIndex);                final float yDiff = Math.abs(y - mLastMotionY);                final int scrollX = getScrollX();                final boolean atEdge = (dx > 0 && scrollX == 0) || (dx < 0 && mAdapter != null &&                        scrollX >= (mAdapter.getCount() - 1) * getWidth() - 1);                if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);                if (canScroll(this, false, (int) dx, (int) x, (int) y)) {                    // Nested view has scrollable area under this point. Let it be handled there.                    mInitialMotionX = mLastMotionX = x;                    mLastMotionY = y;                    return false;                }                if (xDiff > mTouchSlop && xDiff > yDiff) {                    if (DEBUG) Log.v(TAG, "Starting drag!");                    mIsBeingDragged = true;                    setScrollState(SCROLL_STATE_DRAGGING);                    mLastMotionX = x;                    setScrollingCacheEnabled(true);                } else {                    if (yDiff > mTouchSlop) {                        // The finger has moved enough in the vertical                        // direction to be counted as a drag...  abort                        // any attempt to drag horizontally, to work correctly                        // with children that have scrolling containers.                        if (DEBUG) Log.v(TAG, "Starting unable to drag!");                        mIsUnableToDrag = true;                    }                }                break;            }            case MotionEvent.ACTION_DOWN: {                /*                 * Remember location of down touch.                 * ACTION_DOWN always refers to pointer index 0.                 */                mLastMotionX = mInitialMotionX = ev.getX();                mLastMotionY = ev.getY();                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);                if (mScrollState == SCROLL_STATE_SETTLING) {                    // Let the user 'catch' the pager as it animates.                    mIsBeingDragged = true;                    mIsUnableToDrag = false;                    setScrollState(SCROLL_STATE_DRAGGING);                } else {                    completeScroll();                    mIsBeingDragged = false;                    mIsUnableToDrag = false;                }                if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY                        + " mIsBeingDragged=" + mIsBeingDragged                        + "mIsUnableToDrag=" + mIsUnableToDrag);                break;            }            case MotionEventCompat.ACTION_POINTER_UP:                onSecondaryPointerUp(ev);                break;        }        /*        * The only time we want to intercept motion events is if we are in the        * drag mode.        */        return false;    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (mFakeDragging) {            // A fake drag is in progress already, ignore this real one            // but still eat the touch events.            // (It is likely that the user is multi-touching the screen.)            return true;        }        if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {            // Don't handle edge touches immediately -- they may actually belong to one of our            // descendants.            return false;        }        if (mAdapter == null || mAdapter.getCount() == 0) {            // Nothing to present or scroll; nothing to touch.            return false;        }        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(ev);        final int action = ev.getAction();        boolean needsInvalidate = false;        switch (action & MotionEventCompat.ACTION_MASK) {            case MotionEvent.ACTION_DOWN: {                /*                 * If being flinged and user touches, stop the fling. isFinished                 * will be false if being flinged.                 */                completeScroll();                // Remember where the motion event started                mLastMotionX = mInitialMotionX = ev.getX();                mActivePointerId = MotionEventCompat.getPointerId(ev, 0);                break;            }            case MotionEvent.ACTION_MOVE:                if (!mIsBeingDragged) {                    final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);                    final float x = MotionEventCompat.getX(ev, pointerIndex);                    final float xDiff = Math.abs(x - mLastMotionX);                    final float y = MotionEventCompat.getY(ev, pointerIndex);                    final float yDiff = Math.abs(y - mLastMotionY);                    if (DEBUG)                        Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);                    if (xDiff > mTouchSlop && xDiff > yDiff) {                        if (DEBUG) Log.v(TAG, "Starting drag!");                        mIsBeingDragged = true;                        mLastMotionX = x;                        setScrollState(SCROLL_STATE_DRAGGING);                        setScrollingCacheEnabled(true);                    }                }                if (mIsBeingDragged) {                    // Scroll to follow the motion event                    final int activePointerIndex = MotionEventCompat.findPointerIndex(                            ev, mActivePointerId);                    final float x = MotionEventCompat.getX(ev, activePointerIndex);                    final float deltaX = mLastMotionX - x;                    mLastMotionX = x;                    float oldScrollX = getScrollX();                    float scrollX = oldScrollX + deltaX;                    final int width = getWidth();                    final int widthWithMargin = width + mPageMargin;                    final int lastItemIndex = mAdapter.getCount() - 1;                    final float leftBound = Math.max(0, (mCurItem - 1) * widthWithMargin);                    final float rightBound =                            Math.min(mCurItem + 1, lastItemIndex) * widthWithMargin;                    if (scrollX < leftBound) {                        if (leftBound == 0) {                            float over = -scrollX;                            needsInvalidate = mLeftEdge.onPull(over / width);                        }                        scrollX = leftBound;                    } else if (scrollX > rightBound) {                        if (rightBound == lastItemIndex * widthWithMargin) {                            float over = scrollX - rightBound;                            needsInvalidate = mRightEdge.onPull(over / width);                        }                        scrollX = rightBound;                    }                    // Don't lose the rounded component                    mLastMotionX += scrollX - (int) scrollX;                    scrollTo((int) scrollX, getScrollY());                    if (mOnPageChangeListener != null) {                        final int position = (int) scrollX / widthWithMargin;                        final int positionOffsetPixels = (int) scrollX % widthWithMargin;                        final float positionOffset = (float) positionOffsetPixels / widthWithMargin;                        mOnPageChangeListener.onPageScrolled(position, positionOffset,                                positionOffsetPixels);                    }                }                break;            case MotionEvent.ACTION_UP:                if (mIsBeingDragged) {                    final VelocityTracker velocityTracker = mVelocityTracker;                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);                    int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(                            velocityTracker, mActivePointerId);                    mPopulatePending = true;                    final int widthWithMargin = getWidth() + mPageMargin;                    final int scrollX = getScrollX();                    final int currentPage = scrollX / widthWithMargin;                    int nextPage = initialVelocity > 0 ? currentPage : currentPage + 1;                    setCurrentItemInternal(nextPage, true, true, initialVelocity);                    mActivePointerId = INVALID_POINTER;                    endDrag();                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();                }                break;            case MotionEvent.ACTION_CANCEL:                if (mIsBeingDragged) {                    setCurrentItemInternal(mCurItem, true, true);                    mActivePointerId = INVALID_POINTER;                    endDrag();                    needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();                }                break;            case MotionEventCompat.ACTION_POINTER_DOWN: {                final int index = MotionEventCompat.getActionIndex(ev);                final float x = MotionEventCompat.getX(ev, index);                mLastMotionX = x;                mActivePointerId = MotionEventCompat.getPointerId(ev, index);                break;            }            case MotionEventCompat.ACTION_POINTER_UP:                onSecondaryPointerUp(ev);                mLastMotionX = MotionEventCompat.getX(ev,                        MotionEventCompat.findPointerIndex(ev, mActivePointerId));                break;        }        if (needsInvalidate) {            invalidate();        }        return false;    }    @Override    public void draw(Canvas canvas) {        super.draw(canvas);        boolean needsInvalidate = false;        final int overScrollMode = ViewCompat.getOverScrollMode(this);        if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||                (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS &&                        mAdapter != null && mAdapter.getCount() > 1)) {            if (!mLeftEdge.isFinished()) {                final int restoreCount = canvas.save();                final int height = getHeight() - getPaddingTop() - getPaddingBottom();                canvas.rotate(270);                canvas.translate(-height + getPaddingTop(), 0);                mLeftEdge.setSize(height, getWidth());                needsInvalidate |= mLeftEdge.draw(canvas);                canvas.restoreToCount(restoreCount);            }            if (!mRightEdge.isFinished()) {                final int restoreCount = canvas.save();                final int width = getWidth();                final int height = getHeight() - getPaddingTop() - getPaddingBottom();                final int itemCount = mAdapter != null ? mAdapter.getCount() : 1;                canvas.rotate(90);                canvas.translate(-getPaddingTop(),                        -itemCount * (width + mPageMargin) + mPageMargin);                mRightEdge.setSize(height, width);                needsInvalidate |= mRightEdge.draw(canvas);                canvas.restoreToCount(restoreCount);            }        } else {            mLeftEdge.finish();            mRightEdge.finish();        }        if (needsInvalidate) {            // Keep animating            invalidate();        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        // Draw the margin drawable if needed.        if (mPageMargin > 0 && mMarginDrawable != null) {            final int scrollX = getScrollX();            final int width = getWidth();            final int offset = scrollX % (width + mPageMargin);            if (offset != 0) {                // Pages fit completely when settled; we only need to draw when in between                final int left = scrollX - offset + width;                mMarginDrawable.setBounds(left, 0, left + mPageMargin, getHeight());                mMarginDrawable.draw(canvas);            }        }    }    /**     * Start a fake drag of the pager.     * <p>     * <p>A fake drag can be useful if you want to synchronize the motion of the ViewPager     * with the touch scrolling of another view, while still letting the ViewPager     * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.)     * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call     * {@link #endFakeDrag()} to complete the fake drag and fling as necessary.     * <p>     * <p>During a fake drag the ViewPager will ignore all touch events. If a real drag     * is already in progress, this method will return false.     *     * @return true if the fake drag began successfully, false if it could not be started.     * @see #fakeDragBy(float)     * @see #endFakeDrag()     */    public boolean beginFakeDrag() {        if (mIsBeingDragged) {            return false;        }        mFakeDragging = true;        setScrollState(SCROLL_STATE_DRAGGING);        mInitialMotionX = mLastMotionX = 0;        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        } else {            mVelocityTracker.clear();        }        final long time = SystemClock.uptimeMillis();        final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0);        mVelocityTracker.addMovement(ev);        ev.recycle();        mFakeDragBeginTime = time;        return true;    }    /**     * End a fake drag of the pager.     *     * @see #beginFakeDrag()     * @see #fakeDragBy(float)     */    public void endFakeDrag() {        if (!mFakeDragging) {            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");        }        final VelocityTracker velocityTracker = mVelocityTracker;        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);        int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(                velocityTracker, mActivePointerId);        mPopulatePending = true;        if ((Math.abs(initialVelocity) > mMinimumVelocity)                || Math.abs(mInitialMotionX - mLastMotionX) >= (getWidth() / 3)) {            if (mLastMotionX > mInitialMotionX) {                setCurrentItemInternal(mCurItem - 1, true, true);            } else {                setCurrentItemInternal(mCurItem + 1, true, true);            }        } else {            setCurrentItemInternal(mCurItem, true, true);        }        endDrag();        mFakeDragging = false;    }    /**     * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first.     *     * @param xOffset Offset in pixels to drag by.     * @see #beginFakeDrag()     * @see #endFakeDrag()     */    public void fakeDragBy(float xOffset) {        if (!mFakeDragging) {            throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first.");        }        mLastMotionX += xOffset;        float scrollX = getScrollX() - xOffset;        final int width = getWidth();        final int widthWithMargin = width + mPageMargin;        final float leftBound = Math.max(0, (mCurItem - 1) * widthWithMargin);        final float rightBound =                Math.min(mCurItem + 1, mAdapter.getCount() - 1) * widthWithMargin;        if (scrollX < leftBound) {            scrollX = leftBound;        } else if (scrollX > rightBound) {            scrollX = rightBound;        }        // Don't lose the rounded component        mLastMotionX += scrollX - (int) scrollX;        scrollTo((int) scrollX, getScrollY());        if (mOnPageChangeListener != null) {            final int position = (int) scrollX / widthWithMargin;            final int positionOffsetPixels = (int) scrollX % widthWithMargin;            final float positionOffset = (float) positionOffsetPixels / widthWithMargin;            mOnPageChangeListener.onPageScrolled(position, positionOffset,                    positionOffsetPixels);        }        // Synthesize an event for the VelocityTracker.        final long time = SystemClock.uptimeMillis();        final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE,                mLastMotionX, 0, 0);        mVelocityTracker.addMovement(ev);        ev.recycle();    }    /**     * Returns true if a fake drag is in progress.     *     * @return true if currently in a fake drag, false otherwise.     * @see #beginFakeDrag()     * @see #fakeDragBy(float)     * @see #endFakeDrag()     */    public boolean isFakeDragging() {        return mFakeDragging;    }    private void onSecondaryPointerUp(MotionEvent ev) {        final int pointerIndex = MotionEventCompat.getActionIndex(ev);        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);        if (pointerId == mActivePointerId) {            // This was our active pointer going up. Choose a new            // active pointer and adjust accordingly.            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;            mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex);            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);            if (mVelocityTracker != null) {                mVelocityTracker.clear();            }        }    }    private void endDrag() {        mIsBeingDragged = false;        mIsUnableToDrag = false;        if (mVelocityTracker != null) {            mVelocityTracker.recycle();            mVelocityTracker = null;        }    }    private void setScrollingCacheEnabled(boolean enabled) {        if (mScrollingCacheEnabled != enabled) {            mScrollingCacheEnabled = enabled;            if (USE_CACHE) {                final int size = getChildCount();                for (int i = 0; i < size; ++i) {                    final View child = getChildAt(i);                    if (child.getVisibility() != GONE) {                        child.setDrawingCacheEnabled(enabled);                    }                }            }        }    }    /**     * Tests scrollability within child views of v given a delta of dx.     *     * @param v      View to test for horizontal scrollability     * @param checkV Whether the view v passed should itself be checked for scrollability (true),     *               or just its children (false).     * @param dx     Delta scrolled in pixels     * @param x      X coordinate of the active touch point     * @param y      Y coordinate of the active touch point     * @return true if child views of v can be scrolled by delta of dx.     */    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {        if (v instanceof ViewGroup) {            final ViewGroup group = (ViewGroup) v;            final int scrollX = v.getScrollX();            final int scrollY = v.getScrollY();            final int count = group.getChildCount();            // Count backwards - let topmost views consume scroll distance first.            for (int i = count - 1; i >= 0; i--) {                // TODO: Add versioned support here for transformed views.                // This will not work for transformed views in Honeycomb+                final View child = group.getChildAt(i);                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&                        canScroll(child, true, dx, x + scrollX - child.getLeft(),                                y + scrollY - child.getTop())) {                    return true;                }            }        }        return checkV && ViewCompat.canScrollHorizontally(v, -dx);    }    @Override    public boolean dispatchKeyEvent(KeyEvent event) {        // Let the focused view and/or our descendants get the key first        return super.dispatchKeyEvent(event) || executeKeyEvent(event);    }    /**     * You can call this function yourself to have the scroll view perform     * scrolling from a key event, just as if the event had been dispatched to     * it by the view hierarchy.     *     * @param event The key event to execute.     * @return Return true if the event was handled, else false.     */    public boolean executeKeyEvent(KeyEvent event) {        boolean handled = false;        if (event.getAction() == KeyEvent.ACTION_DOWN) {            switch (event.getKeyCode()) {                case KeyEvent.KEYCODE_DPAD_LEFT:                    handled = arrowScroll(FOCUS_LEFT);                    break;                case KeyEvent.KEYCODE_DPAD_RIGHT:                    handled = arrowScroll(FOCUS_RIGHT);                    break;                case KeyEvent.KEYCODE_TAB:                    if (KeyEventCompat.hasNoModifiers(event)) {                        handled = arrowScroll(FOCUS_FORWARD);                    } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {                        handled = arrowScroll(FOCUS_BACKWARD);                    }                    break;            }        }        return handled;    }    public boolean arrowScroll(int direction) {        View currentFocused = findFocus();        if (currentFocused == this) currentFocused = null;        boolean handled = false;        View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused,                direction);        if (nextFocused != null && nextFocused != currentFocused) {            if (direction == View.FOCUS_LEFT) {                // If there is nothing to the left, or this is causing us to                // jump to the right, then what we really want to do is page left.                if (currentFocused != null && nextFocused.getLeft() >= currentFocused.getLeft()) {                    handled = pageLeft();                } else {                    handled = nextFocused.requestFocus();                }            } else if (direction == View.FOCUS_RIGHT) {                // If there is nothing to the right, or this is causing us to                // jump to the left, then what we really want to do is page right.                if (currentFocused != null && nextFocused.getLeft() <= currentFocused.getLeft()) {                    handled = pageRight();                } else {                    handled = nextFocused.requestFocus();                }            }        } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) {            // Trying to move left and nothing there; try to page.            handled = pageLeft();        } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) {            // Trying to move right and nothing there; try to page.            handled = pageRight();        }        if (handled) {            playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));        }        return handled;    }    boolean pageLeft() {        if (mCurItem > 0) {            setCurrentItem(mCurItem - 1, true);            return true;        }        return false;    }    boolean pageRight() {        if (mAdapter != null && mCurItem < (mAdapter.getCount() - 1)) {            setCurrentItem(mCurItem + 1, true);            return true;        }        return false;    }    /**     * We only want the current page that is being shown to be focusable.     */    @Override    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {        final int focusableCount = views.size();        final int descendantFocusability = getDescendantFocusability();        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {            for (int i = 0; i < getChildCount(); i++) {                final View child = getChildAt(i);                if (child.getVisibility() == VISIBLE) {                    ItemInfo ii = infoForChild(child);                    if (ii != null && ii.position == mCurItem) {                        child.addFocusables(views, direction, focusableMode);                    }                }            }        }        // we add ourselves (if focusable) in all cases except for when we are        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is        // to avoid the focus search finding layouts when a more precise search        // among the focusable children would be more interesting.        if (                descendantFocusability != FOCUS_AFTER_DESCENDANTS ||                        // No focusable descendants                        (focusableCount == views.size())) {            // Note that we can't call the superclass here, because it will            // add all views in.  So we need to do the same thing View does.            if (!isFocusable()) {                return;            }            if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE &&                    isInTouchMode() && !isFocusableInTouchMode()) {                return;            }            if (views != null) {                views.add(this);            }        }    }    /**     * We only want the current page that is being shown to be touchable.     */    @Override    public void addTouchables(ArrayList<View> views) {        // Note that we don't call super.addTouchables(), which means that        // we don't call View.addTouchables().  This is okay because a ViewPager        // is itself not touchable.        for (int i = 0; i < getChildCount(); i++) {            final View child = getChildAt(i);            if (child.getVisibility() == VISIBLE) {                ItemInfo ii = infoForChild(child);                if (ii != null && ii.position == mCurItem) {                    child.addTouchables(views);                }            }        }    }    /**     * We only want the current page that is being shown to be focusable.     */    @Override    protected boolean onRequestFocusInDescendants(int direction,                                                  Rect previouslyFocusedRect) {        int index;        int increment;        int end;        int count = getChildCount();        if ((direction & FOCUS_FORWARD) != 0) {            index = 0;            increment = 1;            end = count;        } else {            index = count - 1;            increment = -1;            end = -1;        }        for (int i = index; i != end; i += increment) {            View child = getChildAt(i);            if (child.getVisibility() == VISIBLE) {                ItemInfo ii = infoForChild(child);                if (ii != null && ii.position == mCurItem) {                    if (child.requestFocus(direction, previouslyFocusedRect)) {                        return true;                    }                }            }        }        return false;    }    @Override    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {        // ViewPagers should only report accessibility info for the current page,        // otherwise things get very confusing.        // TODO: Should this note something about the paging container?        final int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = getChildAt(i);            if (child.getVisibility() == VISIBLE) {                final ItemInfo ii = infoForChild(child);                if (ii != null && ii.position == mCurItem &&                        child.dispatchPopulateAccessibilityEvent(event)) {                    return true;                }            }        }        return false;    }    private class PagerObserver extends DataSetObserver {        @Override        public void onChanged() {            dataSetChanged();        }        @Override        public void onInvalidated() {            dataSetChanged();        }    }}

ShowingPager

package history.six.com.rushingdemo.view;import android.content.Context;import android.graphics.drawable.AnimationDrawable;import android.view.LayoutInflater;import android.view.View;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.TextView;import com.zhy.autolayout.AutoLinearLayout;import history.six.com.rushingdemo.R;import history.six.com.rushingdemo.application.MyApplication;import history.six.com.rushingdemo.interfaces.IResetShowingPageListener;import history.six.com.rushingdemo.utils.CommonUtils;import history.six.com.rushingdemo.utils.NetUtils;public abstract class ShowingPager extends FrameLayout implements View.OnClickListener {    /**     * 定义状态     */    public static final int STATE_LOADING = 1;    public static final int STATE_LOAD_ERROR = 2;    public static final int STATE_LOAD_SUCCESS = 3;    public static final int STATE_NOLOGIN = 4;    private final Context context;    //定义当前状态    public int currentState = STATE_LOADING;//得到当前的状态    private final View view;    private final View showLoadError, showLoading;    private final FrameLayout showFrameLayout;    private final AutoLinearLayout titleLayout;    private final TextView showing_error_tv_reset;    private IResetShowingPageListener iResetShowingPageListener;    private final LayoutParams params;    private final View titleView;    private final ImageView drawableImage;    public ShowingPager(Context context) {        super(context);        this.context = context;        params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);        //获取主布局视图        view = View.inflate(context, R.layout.showing_pager, null);        titleLayout = (AutoLinearLayout) view.findViewById(R.id.showLinearLayoutTitle);        showLoadError = view.findViewById(R.id.showLoadError);        showLoading = view.findViewById(R.id.showLoading);        drawableImage = (ImageView) showLoading.findViewById(R.id.drawableImage);        drawableImage.setImageResource(R.drawable.loading_animation);        AnimationDrawable animationDrawable = (AnimationDrawable) drawableImage.getDrawable();        animationDrawable.start();        showFrameLayout = (FrameLayout) view.findViewById(R.id.showFrameLayout);        this.addView(view, params);        //查找重置按钮        showing_error_tv_reset = (TextView) showLoadError.findViewById(R.id.showing_error_tv_reset);        showing_error_tv_reset.setOnClickListener(this);        //添加title布局        titleView = LayoutInflater.from(getContext()).inflate(R.layout.common_title, null);        titleLayout.addView(titleView, params);        setTitleView(titleView);        /**         * 添加成功视图         */        View successView = setSuccessView();        if (successView == null) {            showFrameLayout.setVisibility(View.GONE);        } else {            showFrameLayout.removeAllViews();            showFrameLayout.addView(successView, params);        }        //设置是否需要Title        titleLayout.setVisibility(needTitleView() ? VISIBLE : GONE);        showPage();    }    //添加成功的视图    public abstract View setSuccessView();    //添加Title    public abstract void setTitleView(View titleView);    //添加Title    public abstract boolean needTitleView();    //设置当前状态    public void setCurrentState(StateType stateType) {        currentState = stateType.currentState;        showPage();    }    private void showPage() {        //在主线程执行        CommonUtils.runOnUIThread(new Runnable() {            @Override            public void run() {                showPageOnUI();            }        });    }    private void showPageOnUI() {        showLoading.setVisibility(currentState == STATE_LOADING ? View.VISIBLE : View.GONE);        showLoadError.setVisibility(currentState == STATE_LOAD_ERROR ? View.VISIBLE : View.GONE);        showFrameLayout.setVisibility(currentState == STATE_LOAD_SUCCESS ? View.VISIBLE : View.GONE);    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.showing_error_tv_reset:                this.setCurrentState(StateType.STATE_LOADING);                if (NetUtils.isHaveNet()) {                    /*if (currentState != STATE_LOADING)                        currentState = STATE_LOADING;                    showPage();                    onLoad();*/                    if (iResetShowingPageListener != null) {                        iResetShowingPageListener.onResetClick(view);                    }                } else {                    MyApplication.getHandler().postDelayed(new Runnable() {                        @Override                        public void run() {                            ShowingPager.this.setCurrentState(StateType.STATE_LOAD_ERROR);                        }                    }, 2000);                }                break;        }    }    /**     * 枚举类     */    public enum StateType {        //请求类型        STATE_LOADING(1), STATE_LOAD_ERROR(2), STATE_LOAD_SUCCESS(3), STATE_NOLOGIN(4);        private final int currentState;        StateType(int currentState) {            this.currentState = currentState;        }        public int getCurrentState() {            return currentState;        }    }    public void setIResetShowingPageListener(IResetShowingPageListener iResetShowingPageListener) {        this.iResetShowingPageListener = iResetShowingPageListener;    }}
0 0
原创粉丝点击