华为仿苹果手机|仿华为ViewPager指示器开发教程

更新时间:2020-09-02    来源:华为路由器    手机版     字体:

【www.bbyears.com--华为路由器】

***本文纯手打,转载注明出处***

 

先看一下效果图:华为荣耀6的主题界面:

 

22 11

 

注意标题下的小圆点,本博客就是为了完成它.

 

思路:

 

布局方面:

 

上方一个LinearLayout,下面是一个ViewPager

 

功能方面:

 

LinearLayout肯定需要自定义,初始时,在第一个”推荐”的下面画上一个小圆点,然后通过viewpager的addOnPageChangeListener里的onPageScrolled方法,完成小圆点位置随页面滑动而变化。其实也挺简单的哈!接下来先上代码,然后讲一下原理。

 

首先自定义一个LinearLayout

MyLinearLayout:

package cn.zmit.myapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.BoringLayout;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;

/**
 * Created by kyle on 2016/3/14.
 */
public class MyLinearLayout extends LinearLayout {
    private int startX;//初始位置X坐标
    private Paint mPaint;
    private int moveX;//移动时不断变化的X坐标

    public MyLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setColor(Color.parseColor("#FFFFFF"));//画笔颜色
        mPaint.setStyle(Paint.Style.FILL);//画笔样式(填充内部)
    }

    public MyLinearLayout(Context context) {
        super(context, null);
    }

    /***
     * 开始画圆
     *
     * @param canvas
     */
    @Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        startX = getWidth() / 8;//最开始位置的X坐标
        canvas.save();//保存
        canvas.drawCircle(startX + moveX, getHeight() - 15, 5, mPaint);
        canvas.restore();//取出
    }

    /***
     * 当手指滑动时调用这个方法(在viewpager的onPageScrolled方法调用)
     *
     * @param position
     * @param Offset
     */
    public void changed(int position, float Offset) {
            moveX = (int) (getWidth() / 4 * Offset + position * getWidth() / 4);
            invalidate();//刷新
    }
}
既然用到ViewPager,当然需要fragment;

MyFragment.java:

package cn.zmit.myapplication;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;


/**
 * Created by Administrator on 2016/3/14.
 */
public class MyFragment extends Fragment {
    public static final String TITLE = "title";

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        TextView textView = new TextView(getActivity());
        textView.setText(getArguments().getString(TITLE));
        textView.setTextColor(Color.parseColor("#000000"));
        textView.setGravity(Gravity.CENTER);
        return textView;
    }

    public static MyFragment getInstance(String title) {
        Bundle pBundle = new Bundle();
        pBundle.putString(TITLE, title);
        MyFragment fragment = new MyFragment();
        fragment.setArguments(pBundle);
        return fragment;
    }
}
MainActivity.java:

 

package cn.zmit.myapplication;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.Window;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MainActivity extends FragmentActivity {
    private MyLinearLayout mLinearLayout;
    private ViewPager mViewpager;
    private FragmentStatePagerAdapter adapter;
    public List lists = Arrays.asList("推荐", "排行", "分类","我的");
    private List list = new ArrayList<>();

    private void assignViews() {
        mLinearLayout = (MyLinearLayout) findViewById(R.id.linearLayout);
        mViewpager = (ViewPager) findViewById(R.id.viewpager);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        assignViews();
        initData();
    }

    private void initData() {
        for (String title : lists) {
            MyFragment fragment = MyFragment.getInstance(title);
            list.add(fragment);
        }
        adapter = new FragmentStatePagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return list.get(position);
            }

            @Override
            public int getCount() {
                return list.size();
            }
        };
        mViewpager.setAdapter(adapter);
        mViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                mLinearLayout.changed(position, positionOffset);
            }

            @Override
            public void onPageSelected(int position) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }


}
好了,接下来开始讲一下原理。

这个例子最重要的地方,大家都能知道,在于自定义的LinearLayout,我们先从这里说起吧。

首先,

private int startX;//初始位置X坐标
private Paint mPaint;
private int moveX;//移动时不断变化的X坐标
startX为初始化原点的x坐标

maveX为当我们滑动ViewPager时动态改变的X数值。

然后,在构造方法中,初始画笔mPaint,设置颜色等属性。

接着,在dispatchDraw方法中执行画图功能,这个方法系统自动调用,主要是分发给子组件进行绘制。

代码解析:

startX = getWidth() / 8;//最开始位置的X坐标
初始化startX为屏幕的1/8,因为布局被分为4块,而原点又要位于每个模块的中间,所以初始的X应该为屏幕宽度的1/8。

canvas.save();//保存
canvas.drawCircle(startX + moveX, getHeight() - 15, 5, mPaint);
canvas.restore();//取出
sava和restore方法用于保存画布画图之前的状态和取出之前的状态,绘图时最好带上,这里不说了,有兴趣的同学可以去了解下。

drawCircle方法,顾名思义,画圆,第一个参数代表当前X坐标;第二个参数是高度,全程固定为布局的高度减去15,

大概在字和底部的中间。这个数值可以自己改,改到自己喜欢为止;第三个参数是半径,这里设为5,同理,可以根据喜好改;第四个参数是画笔,之前初始化完成了,这里直接加进去。

先看一下效果:

1

最后,重头戏来了,大家还记得在之前的ViewPager的addOnPageChangeListener里的onPageScrolled中做了什么吗?没错,在里面调用了一个方法:changed,让我们看一下,这个方法里做了什么

public void changed(int position, float Offset) {
        moveX = (int) (getWidth() / 4 * Offset + position * getWidth() / 4);
        invalidate();//刷新
}
看里面内容,将moveX的值变成了getWidth() / 4 * Offset + position * getWidth() / 4。

这到底是多少呢?先介绍一下两个参数,Offset,即滑动的宽度的百分比,比如我手指向左滑动,那么ViewPager的当前fragment也会随着手指往左边移动,当前fragment被隐藏的宽度占当前fragment的总宽度的百分比,即为Offset。Position就是当前fragment为第几个fragment,第一个的话,postion就为0,因为从0开始嘛!(注意,手指往左滑,position为当前position,手指往右滑,position为当前position-1)

介绍完参数后,开始说一下这个moveX到底变成了多少。

getWidth/4,屏幕宽度的1/4,即一个模块的宽度,乘以Offset,即随着手指滑动,使moveX的数值一直变大,直至正好为一个模块的宽,也就是从一个模块,滑到了另一个模块。听着已经可以了,但是不要忘记,Offset每次滑动后,都会变成0,也就是说,假设就这样完事的话,你只能将小圆点从第一个模块移动到第二个模块,无论你怎么滑。

好了,接着,后面还加了position * getWidth() / 4,即当前fragment的position乘以当前模块的宽,这样就解决了只能滑到第二个模块的问题,因为假设当前fragment为第二个,position为1,原点位于模块2,即“排行”,X的数值为X=startX+moveX;

startX=getWidth() / 8 ;

moveX=getWidth() / 4 * Offset + 1* getWidth() / 4;

当我们没动时,X的数值等于”排行”两字中间的X值,

X=getWidth() / 8+1* getWidth() / 4;

当我们往左滑动,Offset不断变大,直至1,position为1

X=getWidth() / 8+getWidth() / 4 +1* getWidth() / 4;

正好比没滑动时大一个模块,即滑到了第三个模块”分类”

当我们往右滑动,Offset不断变大,直至1,position为0

X=getWidth() / 8+getWidth() / 4 +0* getWidth() / 4;

正好比没滑动时小一个模块,即滑到了第一个模块”推荐”

效果图由于条件限制,没法录制gif,所以大家可以自己把代码运行一下看效果。

总结:这个例子主要是运用了viewGroup的画图功能,自定义了一个带圆点的LinearLayout,随后运用ViewPager的滑动参数,动态改变圆点位置。主要在于了解viewPager的运行机制,还有需要了解画笔的使用。

原文来自 :http://blog.it985.com/15824.html

本文来源:http://www.bbyears.com/luyouqishezhi/96322.html

热门标签

更多>>

本类排行