美文网首页
P2PInvest笔记02

P2PInvest笔记02

作者: GeekGray | 来源:发表于2018-09-27 22:35 被阅读3次

阅读原文

09-HomeFragment中自定义圆形进度条ui-RoundProgress

/**
 * @author: Hashub
 * @WeChat: NGSHMVP
 * @Date: 2018/9/19 21:30
 * @function:自定义的圆形进度条
 */
public class RoundProgress extends View
{
//设置绘制的圆环及文本的属性---->使用自定义属性替换
//    private int roundColor = Color.GRAY;//圆环的颜色
//    private int roundProgressColor = Color.RED;//圆弧的颜色
//    private int textColor = Color.BLUE;//文本的颜色
//
//    private int roundWidth = UIUtils.dp2px(10);//圆环的宽度
//    private int textSize = UIUtils.dp2px(20);//文本的字体大小
//
//    private int max = 100;//圆环的最大值
//    private int progress = 60;//圆环的进度

    //使用自定义属性来初始化如下的变量
    private int roundColor;//圆环的颜色
    private int roundProgressColor;//圆弧的颜色
    private int textColor;//文本的颜色

    private float roundWidth;//圆环的宽度
    private float textSize;//文本的字体大小

    private int max;//圆环的最大值
    private int progress;//圆环的进度

    private int width;//当前视图的宽度(=高度)

    private Paint paint;//画笔

    public RoundProgress(Context context)
    {
        this(context, null);
    }

    public RoundProgress(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public RoundProgress(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);

        //初始化画笔
        paint = new Paint();
        paint.setAntiAlias(true);//去除毛边

        //获取自定义的属性
        //1.获取TypeArray的对象(调用两个参数的方法)
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgress);

        //2.取出所有的自定义属性
        roundColor = typedArray.getColor(R.styleable.RoundProgress_roundColor, Color.GRAY);
        roundProgressColor = typedArray.getColor(R.styleable.RoundProgress_roundProgressColor, Color.RED);
        textColor = typedArray.getColor(R.styleable.RoundProgress_textColor, Color.GREEN);
        roundWidth = typedArray.getDimension(R.styleable.RoundProgress_roundWith, UIUtils.dp2px(10));
        textSize = typedArray.getDimension(R.styleable.RoundProgress_textSize, UIUtils.dp2px(20));
        max = typedArray.getInteger(R.styleable.RoundProgress_max, 100);
        progress = typedArray.getInteger(R.styleable.RoundProgress_progress, 30);

        //3.回收处理
        typedArray.recycle();
    }

    public int getMax()
    {
        return max;
    }

    public void setMax(int max)
    {
        this.max = max;
    }

    public int getProgress()
    {
        return progress;
    }

    public void setProgress(int progress)
    {
        this.progress = progress;
    }

    //测量:获取当前视图宽高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = this.getMeasuredWidth();
    }


    /**
     * canvas:画布,对应着视图在布局中的范围区间。范围的左上顶点即为坐标原点
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas)
    {
        //1.绘制圆环
        //获取圆心坐标
        int cx = width / 2;
        int cy = width / 2;
        float radius = width / 2 - roundWidth / 2;
        paint.setColor(roundColor);//设置画笔颜色
        paint.setStyle(Paint.Style.STROKE);//设置圆环的样式
        paint.setStrokeWidth(roundWidth);//设置圆环的宽度
        canvas.drawCircle(cx, cy, radius, paint);

        //2.绘制圆弧
        RectF rectF = new RectF(roundWidth / 2, roundWidth / 2, width - roundWidth / 2, width - roundWidth / 2);
        paint.setColor(roundProgressColor);//设置画笔颜色
        canvas.drawArc(rectF, 0, progress * 360 / max, false, paint);

        //3.绘制文本
        String text = progress * 100 / max + "%";
        //设置paint
        paint.setColor(textColor);
        paint.setTextSize(textSize);
        paint.setStrokeWidth(0);
        Rect rect = new Rect();//创建了一个矩形,此时矩形没有具体的宽度和高度
        paint.getTextBounds(text, 0, text.length(), rect);//此时的矩形的宽度和高度即为整好包裹文本的矩形的宽高
        //获取左下顶点的坐标
        int x = width / 2 - rect.width() / 2;
        int y = width / 2 + rect.height() / 2;


        canvas.drawText(text, x, y, paint);

    }
}

010-HomeFragment中自定义ui-MyScrollView,实现头尾部的下拉、上拉

/**
 * @author: Hashub
 * @WeChat: NGSHMVP
 * @Date: 2018/9/19 21:31
 * @function:自定义尾部上拉下拉
 */
public class MyScrollView extends ScrollView
{
    private View childView;

    public MyScrollView(Context context)
    {
        super(context);
    }

    public MyScrollView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
    }

    //获取子视图
    @Override
    protected void onFinishInflate()
    {
        super.onFinishInflate();
        if (getChildCount() > 0)
        {
            childView = getChildAt(0);
        }
    }

    private int lastY;//上一次y轴方向操作的坐标位置
    private Rect normal = new Rect();//用于记录临界状态的左、上、右、下
    private boolean isFinishAnimation = true;//是否动画结束

    private int lastX, downX, downY;

    //拦截:实现父视图对子视图的拦截
    //是否拦截成功,取决于方法的返回值。返回值true:拦截成功。反之,拦截失败
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev)
    {
        boolean isIntercept = false;
        int eventX = (int) ev.getX();
        int eventY = (int) ev.getY();
        switch (ev.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                lastX = downX = eventX;
                lastY = downY = eventY;
                break;
            case MotionEvent.ACTION_MOVE:
                //获取水平和垂直方向的移动距离
                int absX = Math.abs(eventX - downX);
                int absY = Math.abs(eventY - downY);

                if (absY > absX && absY >= UIUtils.dp2px(10))
                {
                    isIntercept = true;//执行拦截
                }

                lastX = eventX;
                lastY = eventY;
                break;
        }

        return isIntercept;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev)
    {
        if (childView == null || !isFinishAnimation)
        {
            return super.onTouchEvent(ev);
        }

        int eventY = (int) ev.getY();//获取当前的y轴坐标
        switch (ev.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                lastY = eventY;
                break;
            case MotionEvent.ACTION_MOVE:

                int dy = eventY - lastY;//微小的移动量

                if (isNeedMove())
                {
                    if (normal.isEmpty())
                    {
                        //记录了childView的临界状态的左、上、右、下
                        normal.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());

                    }
                    //重新布局
                    childView.layout(childView.getLeft(), childView.getTop() + dy / 2, childView.getRight(), childView.getBottom() + dy / 2);
                }

                lastY = eventY;//重新赋值
                break;
            case MotionEvent.ACTION_UP:
                if (isNeedAnimation())
                {
                    //使用平移动画
                    int translateY = childView.getBottom() - normal.bottom;
                    TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, -translateY);
                    translateAnimation.setDuration(200);
//                translateAnimation.setFillAfter(true);//停留在最终位置上

                    translateAnimation.setAnimationListener(new Animation.AnimationListener()
                    {
                        @Override
                        public void onAnimationStart(Animation animation)
                        {
                            isFinishAnimation = false;
                        }

                        @Override
                        public void onAnimationEnd(Animation animation)
                        {
                            isFinishAnimation = true;
                            childView.clearAnimation();//清除动画
                            //重新布局
                            childView.layout(normal.left, normal.top, normal.right, normal.bottom);
                            //清除normal的数据
                            normal.setEmpty();
                        }

                        @Override
                        public void onAnimationRepeat(Animation animation)
                        {

                        }
                    });

                    //启动动画
                    childView.startAnimation(translateAnimation);
                }


                break;
        }


        return super.onTouchEvent(ev);
    }

    //判断是否需要执行平移动画
    private boolean isNeedAnimation()
    {
        return !normal.isEmpty();

    }

    private boolean isNeedMove()
    {
        int childMeasuredHeight = childView.getMeasuredHeight();//获取子视图的高度
        int scrollViewMeasuredHeight = this.getMeasuredHeight();//获取布局的高度

        Log.e("TAG", "childMeasuredHeight = " + childMeasuredHeight);
        Log.e("TAG", "scrollViewMeasuredHeight = " + scrollViewMeasuredHeight);

        int dy = childMeasuredHeight - scrollViewMeasuredHeight;//dy >= 0

        int scrollY = this.getScrollY();//获取用户在y轴方向上的偏移量 (上 + 下 -)
        if (scrollY <= 0 || scrollY >= dy)
        {
            return true;//按照我们自定义的MyScrollView的方式处理
        }
        //其他处在临界范围内的,返回false。即表示,仍按照ScrollView的方式处理
        return false;
    }
}

011-BaseFragment的抽取

public abstract class BaseFragment extends Fragment
{
    private LoadingPage loadingPage;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        loadingPage = new LoadingPage(container.getContext())
        {

            @Override
            public int layoutId()
            {
                return getLayoutId();
            }

            @Override
            protected void onSuccss(ResultState resultState, View view_success)
            {
                ButterKnife.bind(BaseFragment.this, view_success);
                initTitle();
                initData(resultState.getContent());
            }

            @Override
            protected RequestParams params()
            {
                return getParams();
            }

            @Override
            public String url()
            {
                return getUrl();
            }
        };


        return loadingPage;
    }



    /**
     * 为了保证loadingPage不为null
     * @param savedInstanceState
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState)
    {
        super.onActivityCreated(savedInstanceState);

        getDataFromNet();
    }

    protected abstract RequestParams getParams();

    protected abstract String getUrl();

    //初始化界面的数据
    protected abstract void initData(String content);

    //初始化title
    protected abstract void initTitle();

    //提供布局
    public abstract int getLayoutId();

    @Override
    public void onDestroyView()
    {
        super.onDestroyView();
        ButterKnife.unbind(this);
    }

    public void getDataFromNet()
    {
        loadingPage.getDataFromNet();
    }

}

012-LoadingPage的抽取

提供抽象的LoadingPage

/**
 * @author: Hashub
 * @WeChat: NGSHMVP
 * @Date: 2018/9/19 18:51
 * @function:根据实际联网获取数据情况加载不同的界面
 */
public abstract class LoadingPage extends FrameLayout
{
    //1.定义4种不同的显示状态
    private static final int STATE_LOADING = 1;
    private static final int STATE_ERROR = 2;
    private static final int STATE_EMPTY = 3;
    private static final int STATE_SUCCESS = 4;

    private int state_current = STATE_LOADING;//默认情况下,当前状态为正在加载

    //2.提供4种不同的界面
    private View view_loading;
    private View view_error;
    private View view_empty;
    private View view_success;
    private LayoutParams params;

    private ResultState resultState;//状态枚举类对象

    public LoadingPage(Context context)
    {
        this(context, null);
    }

    public LoadingPage(Context context, AttributeSet attrs)
    {
        this(context, attrs, 0);
    }

    public LoadingPage(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);

        initLayout();//初始化布局
    }

    /**
     * 初始化布局方法
     */
    private void initLayout()
    {
        //实例化view
        //1.提供布局显示的参数
        params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        if (view_loading == null)
        {
            //2.加载布局
            view_loading =  UIUtils.getView(R.layout.page_loading);
            //3.添加到当前的frameLayout中
            addView(view_loading, params);//viewGroup中的addView()方法
        }

        if (view_empty == null)
        {
            //2.加载布局
            view_empty = UIUtils.getView(R.layout.page_empty);
            //3.添加到当前的frameLayout中
            addView(view_empty, params);
        }

        if (view_error == null)
        {
            //2.加载布局
            view_error = UIUtils.getView(R.layout.page_error);
            //3.添加到当前的frameLayout中
            addView(view_error, params);
        }

        showSafePage();
    }

    /**
     * 保证如下的操作在主线程中执行的:更新界面
     */
    private void showSafePage()
    {
        UIUtils.runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                //保证run()中的操作在主线程中执行
                showPage();
            }
        });
    }

    /**
     * 四套界面实际上是叠加显示的,根据当前state_current的值,决定显示哪个view,隐藏其他view
     */
    private void showPage()
    {
        view_loading.setVisibility(state_current == STATE_LOADING ? View.VISIBLE : View.INVISIBLE);
        view_error.setVisibility(state_current == STATE_ERROR ? View.VISIBLE : View.INVISIBLE);
        view_empty.setVisibility(state_current == STATE_EMPTY ? View.VISIBLE : View.INVISIBLE);

        if (view_success == null)
        {
            view_success = UIUtils.getView(layoutId());
            addView(view_success, params);
        }

        view_success.setVisibility(state_current == STATE_SUCCESS ? View.VISIBLE : View.INVISIBLE);
    }

    /**
     * 在getDataFromNet()中实现联网加载数据
     */
    public void getDataFromNet()
    {
        String url = url();
        //如果页面不需要联网请求,即url为空,则成功显示本身页面
        if (TextUtils.isEmpty(url))
        {
            resultState = ResultState.SUCCESS;
            resultState.setContent("");
            return;
        }
        //如果不为空,根据实际url联网请求数据
        //模拟联网延迟2s效果
        UIUtils.getHandler().postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                AsyncHttpClient client = new AsyncHttpClient();
                client.get(url(), params(), new AsyncHttpResponseHandler()
                {
                    @Override
                    public void onSuccess(String content)
                    {
                        if (TextUtils.isEmpty(content))
                        {// "" or null
//                    state_current = STATE_EMPTY;
                            resultState = ResultState.EMPTY;
                            resultState.setContent("");
                        }
                        else
                        {
//                    state_current = STATE_SUCCESS;
                            resultState = ResultState.SUCCESS;
                            resultState.setContent(content);
                        }

//                showSafePage();
                        loadPage();
                    }

                    @Override
                    public void onFailure(Throwable error, String content)
                    {
//                state_current = STATE_ERROR;
                        resultState = ResultState.ERROR;
                        resultState.setContent("");

//                showSafePage();
                        loadPage();

                    }
                });
            }
        }, 2000);
    }

    private void loadPage()
    {
        switch (resultState)
        {
            case ERROR:
                state_current = STATE_ERROR;
                break;
            case EMPTY:
                state_current = STATE_EMPTY;
                break;
            case SUCCESS:
                state_current = STATE_SUCCESS;
                break;
        }
        //根据修改以后的state_current,更新视图的显示。
        showSafePage();

        if (state_current == STATE_SUCCESS)
        {
            onSuccss(resultState, view_success);
        }
    }

    /**
     * 抽象方法,当显示的是成功界面时,加载的是实际的fragment布局
     *
     * @return
     */
    public abstract int layoutId();


    /**
     * 提供联网的请求参数
     *
     * @return
     */
    protected abstract RequestParams params();


    /**
     * 提供联网的请求地址
     *
     * @return
     */
    public abstract String url();

    /**
     * 成功显示的页面
     * @param resultState
     * @param view_success
     */
    protected abstract void onSuccss(ResultState resultState, View view_success);

    /**
     * 提供枚举类,封装联网以后的状态值和数据
     */
    public enum ResultState
    {
        //public static final ERROR=new ResultState(2);一样的部分省略,不同的抽取出来,用逗号隔开
        ERROR(2), EMPTY(3), SUCCESS(4);

        int state;

        ResultState(int state)
        {
            this.state = state;
        }

        private String content;

        public String getContent()
        {
            return content;
        }

        public void setContent(String content)
        {
            this.content = content;
        }
    }
}

013-投资模块布局fragment_invest.xml的设置

上面是:TabPageIndicator

下面是:ViewPager + Fragment(3个:ProductListFragment,ProductRecommondFragment,ProductHotFragment)

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical"
        >
    
        <include layout="@layout/common_title"></include>
    
        <com.viewpagerindicator.TabPageIndicator
            android:id="@+id/tabpage_invest"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"></com.viewpagerindicator.TabPageIndicator>
    
        <android.support.v4.view.ViewPager
            android:id="@+id/vp_invest"
            android:layout_width="match_parent"
            android:layout_height="match_parent"></android.support.v4.view.ViewPager>
    
    </LinearLayout>

014-ViewPager+FragmentPagerAdapter显示投资整体模块数据

/**
 * @author: Hashub
 * @WeChat: NGSHMVP
 * @Date: 2018/9/15 14:39
 * @function:投资理财fragment
 */
public class InvestFragment extends BaseFragment
{
    @Bind(R.id.iv_title_back)
    ImageView ivTitleBack;
    @Bind(R.id.tv_title)
    TextView tvTitle;
    @Bind(R.id.iv_title_setting)
    ImageView ivTitleSetting;
    @Bind(R.id.tabpage_invest)
    com.viewpagerindicator.TabPageIndicator tabpageInvest;
    @Bind(R.id.vp_invest)
    ViewPager vpInvest;


    @Override
    protected RequestParams getParams()
    {
        return null;
    }

    @Override
    protected String getUrl()
    {
        return null;
    }

    @Override
    protected void initData(String content)
    {
//1.加载三个不同的Fragment:ProductListFragment,ProductRecommondFragment,ProductHotFragment.
        initFragments();
        //2.ViewPager设置三个Fragment的显示
        MyAdapter adapter = new MyAdapter(getFragmentManager());
        vpInvest.setAdapter(adapter);
        //将TabPagerIndicator与ViewPager关联
        tabpageInvest.setViewPager(vpInvest);
    }

    private List<Fragment> fragmentList = new ArrayList<>();

    private void initFragments()
    {
        ProductListFragment productListFragment = new ProductListFragment();
        ProductRecommondFragment productRecommondFragment = new ProductRecommondFragment();
        ProductHotFragment productHotFragment = new ProductHotFragment();
        //添加到集合中
        fragmentList.add(productListFragment);
        fragmentList.add(productRecommondFragment);
        fragmentList.add(productHotFragment);
    }


    protected void initTitle()
    {
        ivTitleBack.setVisibility(View.GONE);
        tvTitle.setText("投资");
        ivTitleSetting.setVisibility(View.GONE);
    }

    @Override
    public int getLayoutId()
    {
        return R.layout.fragment_invest;
    }

    /**
     * 提供PagerAdapter的实现
     * 如果ViewPager中加载的是Fragment,则提供的Adpater可以继承于具体的:FragmentStatePagerAdapter或FragmentPagerAdapter
     * FragmentStatePagerAdapter:适用于ViewPager中加载的Fragment过多,会根据最近最少使用算法,实现内存中Fragment的清理,避免溢出
     * FragmentPagerAdapter:适用于ViewPager中加载的Fragment不多时,系统不会清理已经加载的Fragment。
     */
    class MyAdapter extends FragmentPagerAdapter
    {


        public MyAdapter(FragmentManager fm)
        {
            super(fm);
        }

        @Override
        public Fragment getItem(int position)
        {
            return fragmentList.get(position);
        }

        @Override
        public int getCount()
        {
            return fragmentList == null ? 0 : fragmentList.size();
        }

        //提供TabPageIndicator的显示内容
        @Override
        public CharSequence getPageTitle(int position)
        {
            //方式一:
//            if(position == 0){
//                return "全部理财";
//            }else if(position == 1){
//                return "推荐理财";
//            }else if(position == 2){
//                return "热门理财";
//            }
            //方式二:
            return UIUtils.getStringArr(R.array.invest_tab)[position];
        }
    }
}

关于主题:

android:theme="@style/Theme.PageIndicatorDefaults"

创建相应的styles.xml中的主题,并在功能清单文件中使用

<!--自定义viewpagerIndicator样式-->
    <style name="StyledIndicators" parent="@android:style/Theme.Light">
        <item name="vpiTabPageIndicatorStyle">@style/CustomTabPageIndicator</item>
        <item name="android:windowNoTitle">true</item>
    </style>

    <style name="CustomTabPageIndicator" parent="Widget.TabPageIndicator">
        <item name="android:background">@drawable/tab_indicator</item>
        <item name="android:textAppearance">@style/CustomTabPageIndicator.Text</item>
        <item name="android:textSize">14sp</item>
        <item name="android:dividerPadding">8dp</item>
        <item name="android:showDividers">middle</item>
        <item name="android:paddingLeft">10dp</item>
        <item name="android:paddingRight">10dp</item>
        <item name="android:fadingEdge">horizontal</item>
        <item name="android:fadingEdgeLength">8dp</item>
    </style>

    <style name="CustomTabPageIndicator.Text" parent="android:TextAppearance.Medium">
        <item name="android:typeface">monospace</item>
        <item name="android:textColor">@drawable/selector_tabtext</item>
    </style>

关于Context的实现类:Application和Activity的不同

①new AlertDialog.Builder(activity):只能使用activity

②在地图的集成中:只能使用application

③Toast.makeText(application/activity):都可以使用

④View.inflate(activity,..):二者都可,但建议使用activity

⑤new TextView(activity);二者都可,但建议使用activity.

⑥其他情况下,如果使用activity会造成内存泄漏的话,建议替换为application。

相关文章

  • P2PInvest笔记02

    阅读原文 09-HomeFragment中自定义圆形进度条ui-RoundProgress 010-HomeFra...

  • P2PInvest笔记01

    阅读原文 P2P金融 内容大纲 什么是p2p P2P金融又叫P2P信贷 信贷:信用贷款 P2P金融指个人与个人间的...

  • P2PInvest笔记04

    阅读原文 025-支付功能的集成 1.充值业务 2.提现业务 p2p金融项目当中的提现业务: 1.并不是即时到账 ...

  • P2PInvest笔记03

    阅读原文 015-显示"全部理财"模块数据 1. 布局fragment_invest.xml 2. 跑马灯效果...

  • 笔记01:MySQL server安装

    window 安装MySQL server 笔记02:笔记02:sqlalchemy-连接MySQL笔记03:sq...

  • 目录

    羊皮笔记01 羊皮笔记02 羊皮笔记03 羊皮笔记04 羊皮笔记05 羊皮笔记06 羊皮笔记07

  • JavaScript 笔记02(js 循环 / 函数参数 / j

    JavaScript 笔记02 接笔记01 5.for / forEach / for-in / for-of 不...

  • VBA学习笔记-02

    VBA学习笔记 笔记摘抄自EXCEL精英培训-蓝色幻想 VBA学习笔记01(链接)VBA学习笔记02 (链接) 目...

  • VBA学习笔记-01

    VBA学习笔记 笔记摘抄自EXCEL精英培训-蓝色幻想 VBA学习笔记01(链接)VBA学习笔记02 (链接) 目...

  • 【课程笔记】一个概念“秒杀”所有学习方法

    基本信息: 课程时间:2017-02-03 听课时间:2017-02-11 笔记时间:2017-02-11 分享老...

网友评论

      本文标题:P2PInvest笔记02

      本文链接:https://www.haomeiwen.com/subject/vnwyoftx.html