下面的知识点呢,是自己第一次做这个效果,记录下知识,不知道有没有更好的实现方法。
文章二------改进版
在Android项目中有些引导页上面是一些小图组合成的,背景颜色是纯色的,每一张颜色不同,这种情况呢,导致在滑动展示引导页的时候,切换效果的颜色变化感觉很生硬。本文讲解实现根据滑动逐渐改变背景颜色的一个效果。
先看看效果图,如下:
1、主要依赖:
compile'com.android.support:support-v4:23.4.0'
compile'com.readystatesoftware.systembartint:systembartint:1.0.4'
第一个呢大家比较熟悉,就不多说了(确实不知道的呢,俺也莫法了,找度娘或者姑姑吧,哈哈);第二个呢,主要是沉浸式状态栏的一个运用依赖,是状态栏颜色也跟着变化,看着就更舒服了,对吧!版本号的话就只有大家根据官方的自己更新了。下面贴出这个状态栏依赖的官方地址与介绍,大家可以看看:
Maven中央仓库
github代码地址
2、代码部分
代码实现呢,用的东西很简单。
1、布局文件,也就是ViewPager的使用。xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/rl_root"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.AppIntroActivity">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!--<com.center.mycode.view.CirclePageIndicator-->
<!--android:id="@+id/indicator"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_alignParentBottom="true"-->
<!--android:layout_centerHorizontal="true"-->
<!--android:layout_marginBottom="15dp"/>-->
</RelativeLayout>
其中注释部分是自定义添加的指示器,可以是数字、小圆圈。
2、资源文件代码,我是写在数组文件arrays.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="splash_desc">
<item>第一次写博客</item>
<item>觉得行,来个肯定吧</item>
<item>有不好的地方欢迎大神指点</item>
<item>记得分享哟</item>
</string-array>
<array name="splash_icon">
<item>@mipmap/splash_iv_first</item>
<item>@mipmap/splash_iv_second</item>
<item>@mipmap/splash_iv_third</item>
<item>@mipmap/splash_iv_forth</item>
</array>
<array name="splash_bg">
<item>@color/light_green_500</item>
<item>@color/amber_500</item>
<item>@color/red_400</item>
<item>@color/blue_500</item>
</array>
</resources>
第一个是每一个页面的一些文字;第二个是一些图片、图标;第三个是背景颜色。这些呢都是ViewPager每页所需要的内容,大家可以根据自己的需求修改。(当然demo的话也可以不要这些内容,只需要纯色的背景只是为了好看些,哈哈)。
3、ViewPager的布局,xml如下:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/iv_img"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="2"
android:scaleType="fitEnd"
android:src="@mipmap/splash_iv_first"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:gravity="center_horizontal"
android:textColor="@color/white"
android:textSize="18sp"/>
<Button
android:id="@+id/btn_launch"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_centerInParent="true"
android:background="@color/grey_500"
android:onClick="goToMain"
android:text="立即开启"
android:textColor="@color/white"
android:textSize="18sp"/>
</RelativeLayout>
</LinearLayout>
立即开启按钮可以先进行隐藏,最后一页的时候在显示。
4、主要实现代码:
怎么创建页面、mainfest怎么引用activity、怎么引用控件等基础操作在这就不说了。(后贴出全部代码)
1、首先得到要设置背景颜色的根布局控件:
mRootLayout = (RelativeLayout)findViewById(R.id.rl_root);
2、然后就是ViewPager的使用,得给它设置PagerAdapter:
private class IntroPager extends PagerAdapter
{
private String[] mDescs;
private TypedArray mIcons;
public IntroPager(int icoImage, int des)
{
mDescs = getResources().getStringArray(des);
mIcons = getResources().obtainTypedArray(icoImage);
}
@Override
public int getCount()
{
return mIcons.length();
}
@Override
public boolean isViewFromObject(View view, Object object)
{
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position)
{
View itemLayout = getLayoutInflater().inflate(R.layout.layout_app_intro, container, false);
ImageView mImage = (ImageView)itemLayout.findViewById(R.id.iv_img);
TextView mTextView = (TextView)itemLayout.findViewById(R.id.tv_desc);
Button mButton = (Button)itemLayout.findViewById(R.id.btn_launch);
mImage.setImageResource(mIcons.getResourceId(position, 0));
mTextView.setText(mDescs[position]);
if (position == getCount() - 1)
{
mButton.setVisibility(View.VISIBLE);
}
else
{
mButton.setVisibility(View.GONE);
}
container.addView(itemLayout);
return itemLayout;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object)
{
container.removeView((View)object);
}
}
代码嘛,就不多说,比较简单。重点就是构造方法,的一个资源文件的引用。
3、ViewPager添加滑动监听:
滑动监听的代码是这次的重点,以前用的setOnPageChangeListener,不过已经废除了,得用addOnPageChangeListener,然后实现里面的onPageScrolled方法。如下:
shades = new ColorShades();
colorBg = getResources().getIntArray(R.array.splash_bg);
mRootLayout = (RelativeLayout)findViewById(R.id.rl_root);
mViewPager = (ViewPager)findViewById(R.id.viewpager);
IntroPager introPager = new IntroPager(R.array.splash_icon, R.array.splash_desc);
mViewPager.setAdapter(introPager);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
{
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
shades.setFromColor(colorBg[position % colorBg.length])
.setToColor(colorBg[(position + 1) % colorBg.length])
.setShade(positionOffset);
mRootLayout.setBackgroundColor(shades.generate());
applySelectedColor(shades.generate());
}
@Override
public void onPageSelected(int position)
{
}
@Override
public void onPageScrollStateChanged(int state)
{
}
});
大家都看到了,重点就是ColorShades 和onPageScrolled里面的一个参数结合使用。
(1)先看看onPageScrolled的参数:
position:在非第一页与最后一页时,滑动到下一页,position为当前页位置;滑动到上一页,position为当前页-1。
positionOffset :滑动到下一页,[0,1)区间上变化;滑动到上一页:(1,0]区间上变化。
positionOffsetPixels:这个和positionOffset很像,滑动到下一页,[0,宽度)区间上变化;滑动到上一页:(宽度,0]区间上变化。
第一页时:滑动到上一页position=0 ,其他基本为0 ;最后一页滑动到下一页 position为当前页位置,其他两个参数为0。
由此发现,positionOffset很适合作为,渐变,缩放的控制参数;positionOffsetPixels则可以作为平移等的控制参数。
那么positionOffset就能用来实现滑动切换时背景颜色进行渐变切换。
(2)ColorShades :
主要实现了从哪个颜色变化到哪个颜色,以及引用positionOffset进行控制颜色的渐变,返回RGB组合成的一个新颜色值,我们设置这个颜色值就可以了。代码如下:
/**
* Source from :
https://gist.github.com/cooltechworks/4f37021b1216f773daf8
* Color shades will provide all the intermediate colors between two colors. It just requires a decimal value between
* 0.0 to 1.0
* and it provides the exact shade combination of the two color with this shade value.
* Textual explanation :
*
* White LtGray Gray DkGray Black
* 0 0.25 0.5 0.75 1
* Given two colors as White and Black,and shade
* as 0 gives White
* as 0.25 gives Light gray
* as 0.5 gives Gray
* as 0.75 gives Dark gray
* as 1 gives Black.
*/
public class ColorShades
{
private int mFromColor;
private int mToColor;
private float mShade;
public ColorShades setFromColor(int fromColor)
{
this.mFromColor = fromColor;
return this;
}
public ColorShades setToColor(int toColor)
{
this.mToColor = toColor;
return this;
}
public ColorShades setFromColor(String fromColor)
{
this.mFromColor = Color.parseColor(fromColor);
return this;
}
public ColorShades setToColor(String toColor)
{
this.mToColor = Color.parseColor(toColor);
return this;
}
public ColorShades forLightShade(int color)
{
setFromColor(Color.WHITE);
setToColor(color);
return this;
}
public ColorShades forDarkShare(int color)
{
setFromColor(color);
setToColor(Color.BLACK);
return this;
}
public ColorShades setShade(float shade)
{
this.mShade = shade;
return this;
}
/**
* Generates the shade for the given color.
*
* @return the int value of the shade.
*/
public int generate()
{
int fromR = Color.red(mFromColor);
int fromG = Color.green(mFromColor);
int fromB = Color.blue(mFromColor);
int toR = Color.red(mToColor);
int toG = Color.green(mToColor);
int toB = Color.blue(mToColor);
int diffR = toR - fromR;
int diffG = toG - fromG;
int diffB = toB - fromB;
int red = fromR + (int)((diffR * mShade));
int green = fromG + (int)((diffG * mShade));
int blue = fromB + (int)((diffB * mShade));
return Color.rgb(red, green, blue);
}
/**
* Assumes the from and to color are inverted before generating the shade.
* @return the int value of the inverted shade.
*/
public int generateInverted()
{
int fromR = Color.red(mFromColor);
int fromG = Color.green(mFromColor);
int fromB = Color.blue(mFromColor);
int toR = Color.red(mToColor);
int toG = Color.green(mToColor);
int toB = Color.blue(mToColor);
int diffR = toR - fromR;
int diffG = toG - fromG;
int diffB = toB - fromB;
int red = toR - (int)((diffR * mShade));
int green = toG - (int)((diffG * mShade));
int blue = toB - (int)((diffB * mShade));
return Color.rgb(red, green, blue);
}
/**
* Gets the String equivalent of the generated shade
* @return String value of the shade
*/
public String generateInvertedString()
{
return String.format("#%06X", 0xFFFFFF & generateInverted());
}
/**
* Gets the inverted String equivalent of the generated shade
* @return String value of the shade
*/
public String generateString()
{
return String.format("#%06X", 0xFFFFFF & generate());
}
}
这个是人家造的轮子,源码地址呢也在注释里面。小伙伴可以去看看大牛写的。然后给设置背景颜色:
mRootLayout.setBackgroundColor(shades.generate());
这样呢也就基本完成了滑动渐变背景色的功能,但是这个看起不爽,状态栏的颜色要是也跟着变化,整个屏幕都是一个颜色,更好看了。然后我们就运用到了前面说的第二个依赖包来设置状态栏颜色。怎么使用呢,可以参考前面给出的作者代码地址,然后我也贴出我实现的代码。主要是onCreate方法里面:
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
//透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明导航栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
setContentView(R.layout.activity_app_intro);
mTintManager = new SystemBarTintManager(this);
mTintManager.setStatusBarTintEnabled(true);
mTintManager.setNavigationBarTintEnabled(true);
applySelectedColor(R.color.light_green_500);//这里给他设置第一个页面的颜色值
init();
}
//设置状态栏颜色,在onPageScrolled里进行背景颜色一样的设置值。
private void applySelectedColor(int color)
{
mTintManager.setTintColor(color);
}
好了代码基本大概就是这样,然后出来的效果呢,就是展示图那样。
第一次写文章,望大家给出宝贵建议,以及不当之处请斧正,有更好的实现方法,大家也可以联系呀,嘿嘿,大家共同学习。感谢大家!么么哒!
哦,对了,5.0以上运行效果!
网友评论
int colorBg[] = getResources().getIntArray(R.array.splash_bg);
ColorShades shades = new ColorShades();
把viewpager监听里面的这两个东西提出去,进行优化下,避免重复获取和new。
API为19及以上设置为:
(1)已贴出的acyivity代码那样,配置的是大于等于19
(2) style里面配置主题的话:
API为19:
<item name="android:windowTranslucentStatus">true</item>
<!--透明导航栏-->
<item name="android:windowTranslucentNavigation">true</item>
API为21及以上:
<item name="android:windowTranslucentStatus">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
其他,如果要API更低的情况下好看些:
<!--无导航栏 -->
<item name="windowActionBar">false</item>
<!--无标题栏 -->
<item name="windowNoTitle">true</item>
<!--全屏-->
<item name="android:windowFullscreen">true</item>
以上这样设置了后,比如在API为17的时候,就是全屏的,整个也是一个颜色,就比较好看了。
感谢大家指出!
View itemLayout = getLayoutInflater().inflate(R.layout.layout_app_intro, container, false);这句应该改成
View itemLayout = getLayoutInflater().inflate(R.layout.layout_app_intro, null, false);
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
attachToRoot就是那个boolean值。
感谢指出
<item name="android:windowTranslucentStatus">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
设置为透明色就可以自适应颜色的变化就可以了吧?