您的位置:首页 > 移动开发 > 微信开发

android系列微谈一之——仿微信6.0左右滑动渐变切换效果[大陆第一人_求加精]

2014-10-28 17:31 681 查看
<pre name="code" class="java">




----------------------------------------------------------------------------------------------------------介绍:BottomMenuSlideGradientSwipe是一个仿微信6.0左右滑动渐变切换效果的demo,特分享与大家探讨邮箱:lijunhuayc@sina.com QQ:190951132
GitHub账户:lijunhuayc[目前上面只有一个自己写的自定义AlertDialog对话框,有兴趣的朋友可以看一下,当然肯定没得前段时间出来的那个专门的动画对话框好哈]群里很多网友多次讨论过新版微信6.0的滑动渐变导航[底部菜单渐变切换]的效果怎么做的,今儿个空了在网上搜了一下,几乎没搜到啥有用信息,唯独有一个说的是用高斯函数对图片进行渐变显隐藏[通过透明度],但这并不能达到效果。你是不是也想知道微信开发者是怎么实现的呢?那么请往下看……

针对于此问题,我特地自己来实现此效果。
先看效果图:







内容左右滑动我们可以用很成功的JazzyViewPager来实现,它自带多种动画,其中有一个方法animateFade()就是控制渐变的,但它受到一个属性mFadeEnabled的影响,所以初始化的时候要确保mFadeEnabled属性
的值为true
首先介绍一下使用到的开源库:
master-JazzyViewPager主要就是用滑动渐变的viewpager

https://github.com/jfeinstein10/JazzyViewPager
NineOldAndroids-library超经典的一个动画库

https://github.com/JakeWharton/NineOldAndroids

----------------------------------------------------------------------------------------------------------
eclipse新建一个项目BottomMenuSlideGradientSwipe

1因为此实现需要修改一点点JazzyViewpager类的源码,所以这里引用方式是直接将master-JazzyViewPager下的所有资源文件和类文件拷贝到项目对应目录下
注意:jazzyviewpager的资源有好几个attrs.xmlcolor.xml
strings.xml 这几个都别忘记了

2将NineOldAndroids-library的jar文件拷贝到libs目录下

3新建一个类MainActivity继承自Activity
先看看布局文件
----------------------------------------------------暂停了一下,唉,开始错了点小错误,现在搞定了。完美运行perfect---------哇咔咔咔咔-----------------------------------

先看布局文件:
activity_main.xml

<pre name="code" class="java"><span style="font-family: Arial, Helvetica, sans-serif;"><TabHost xmlns:android="http://schemas.android.com/apk/res/android"</span>


android:id="@android:id/tabhost"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="#FFFFFF"
            android:visibility="gone" >
        </FrameLayout>

        <com.jfeinstein.jazzyviewpager.JazzyViewPager
            xmlns:app="http://schemas.android.com/apk/res/com.ycg.bottommenuslidegradientswipe"
            android:id="@+id/jazzyPager"
            app:style="standard"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@drawable/main_tabwidget_background"
            android:visibility="visible" />
    </LinearLayout>

</TabHost>


说明:将tabhost用于显示内容的framelayout隐藏掉,然后用一个viewpager来代替 [此处用的是开源的 JazzyViewPager ,它自带很多滑动动画]

main_tabwidget_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp" >

    <LinearLayout
        android:id="@+id/normalLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/normalImg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/scan_book" />

        <TextView
            android:id="@+id/normalTV"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="扫书" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/selectedLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/selectedImage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/scan_book_hl" />

        <TextView
            android:id="@+id/selectedTV"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="扫书"
            android:textColor="#00FF00"
            android:textSize="20sp" />
    </LinearLayout>

</RelativeLayout>


说明:此布局文件是tabwidget 的tab项的布局[我们tabwidget的tab用自定义布局实现,后面会详细说明]

布局中有一个normalLayout 是tab未选中状态 ,一个selectedLayout是tab的选中状态

注意了:有人会问,为什么不用两张图来实现? 问的好,这就是这篇文章的关键点,详情请继续深入......

我们先修改一下啊JazzyViewpager.java 的源码

打开java文件,给jazzyviewpager类添加如下静态内部接口、属性和方法:

public static interface SlideCallback {
		void callBack(int position, float positionOffset);
	}
	private SlideCallback slideCallback = null;
	public void setSlideCallBack(SlideCallback slideCallBack) {
		this.slideCallback = slideCallBack;
	}
用static的原因我相信你看的懂,避免引用的时候去调用外部类的实例。

SlideCallback 接口的作用是在pager滑动的过程中回调改变tab的渐变显示

接着找到 protected void animateFade(View left, View right, float positionOffset) 方法并修改一下

原来的:

protected void animateFade(View left, View right, float positionOffset) {
		if (left != null) {
			ViewHelper.setAlpha(left, 1 - positionOffset);
		}
		if (right != null) {
			ViewHelper.setAlpha(right, positionOffset);
		}
	}


修改后的:

protected void animateFade(View left, View right, float positionOffset, int position) {
		if (left != null) {
			ViewHelper.setAlpha(left, 1 - positionOffset);
			if (slideCallback != null) {
				slideCallback.callBack(position, 1 - positionOffset);
			}
		}
		if (right != null) {
			ViewHelper.setAlpha(right, positionOffset);
			if (slideCallback != null) {
				slideCallback.callBack(position + 1, positionOffset);
			}
		}
	}


animateFade方法的作用就是在页面切换的过程中使用 NineOldAndroids 库设置透明渐变,所以我们就在它渐变的地方调用我们的回调函数来改变界面tab的渐变

animateFade调用的地方只有一个 在onPageScrolled 方法中

将调用方式

animateFade(mLeft, mRight, effectOffset);

改为:animateFade(mLeft, mRight, effectOffset, position); 参数position即为onPageScrolled方法的position参数

JazzyViewpager修改完毕

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面开始界面activity的编写:

这里介绍一个工具库:x-utils-master 一个实现了android中 Ioc 开源库,里面主要有四个类 详细转--github

详情请点击我跳转到另一篇博客【xUtils的使用】

备用连接

----------------------------------------------

MainActivity:如下

完整代码如下:

package com.ycg.bottommenuslidegradientswipe;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TextView;

import com.jfeinstein.jazzyviewpager.JazzyViewPager;
import com.jfeinstein.jazzyviewpager.JazzyViewPager.SlideCallback;
import com.jfeinstein.jazzyviewpager.JazzyViewPager.TransitionEffect;
import com.jfeinstein.jazzyviewpager.OutlineContainer;
import com.lidroid.xutils.ViewUtils;
import com.lidroid.xutils.view.annotation.ViewInject;
import com.nineoldandroids.view.ViewHelper;

public class MainActivity extends Activity {
	@ViewInject(R.id.jazzyPager)
	private JazzyViewPager jazzyPager;
	List<Map<String, View>> tabViews = new ArrayList<Map<String, View>>();
	Context context;
	public TabHost tabHost;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ViewUtils.inject(this);
		context = this;
		ActionBar actionBar = getActionBar();
		actionBar.setTitle("BottomMenuSlideGradientSwipe");
		// --------------------
		tabHost = (TabHost) findViewById(android.R.id.tabhost);
		tabHost.setup();
		tabHost.addTab(tabHost.newTabSpec("0").setIndicator(createTab("主页", 0)).setContent(android.R.id.tabcontent));
		tabHost.addTab(tabHost.newTabSpec("1").setIndicator(createTab("统计", 1)).setContent(android.R.id.tabcontent));
		tabHost.addTab(tabHost.newTabSpec("2").setIndicator(createTab("消息", 2)).setContent(android.R.id.tabcontent));
		tabHost.addTab(tabHost.newTabSpec("3").setIndicator(createTab("设置", 3)).setContent(android.R.id.tabcontent));
		// 点击tabHost 来切换不同的消息
		tabHost.setOnTabChangedListener(new OnTabChangeListener() {
			@Override
			public void onTabChanged(String tabId) {
				int index = Integer.parseInt(tabId);
				setTabSelectedState(index, 4);
				tabHost.getTabContentView().setVisibility(View.GONE);// 隐藏content
				switch (index) {
					case 0:
						break;
					case 1:
						break;
					case 2:
						break;
					case 3:
						break;
				}
			}
		});
		tabHost.setCurrentTab(0);
		initJazzyPager(TransitionEffect.Standard);
	}

	/**
	 * 动态创建 TabWidget 的Tab项,并设置normalLayout的alpha为1,selectedLayout的alpha为0[显示normal,隐藏selected]
	 * @param tabLabelText
	 * @param tabIndex
	 * @return
	 */
	private View createTab(String tabLabelText, int tabIndex) {
		View tabIndicator = LayoutInflater.from(this).inflate(R.layout.main_tabwidget_layout, null);
		ImageView normalImg = (ImageView) tabIndicator.findViewById(R.id.normalImg);
		ImageView selectedImg = (ImageView) tabIndicator.findViewById(R.id.selectedImage);
		TextView normalTV = (TextView) tabIndicator.findViewById(R.id.normalTV);
		TextView selectedTV = (TextView) tabIndicator.findViewById(R.id.selectedTV);
		normalTV.setText(tabLabelText);
		selectedTV.setText(tabLabelText);
		switch (tabIndex) {
			case 0:
				normalImg.setImageResource(R.drawable.scan_book);
				selectedImg.setImageResource(R.drawable.scan_book_hl);
				break;
			case 1:
				normalImg.setImageResource(R.drawable.scan_qr);
				selectedImg.setImageResource(R.drawable.scan_qr_hl);
				break;
			case 2:
				normalImg.setImageResource(R.drawable.scan_street);
				selectedImg.setImageResource(R.drawable.scan_street_hl);
				break;
			case 3:
				normalImg.setImageResource(R.drawable.scan_word);
				selectedImg.setImageResource(R.drawable.scan_word_hl);
				break;
		}
		View normalLayout = tabIndicator.findViewById(R.id.normalLayout);
		normalLayout.setAlpha(1f);// 透明度显示
		View selectedLayout = tabIndicator.findViewById(R.id.selectedLayout);
		selectedLayout.setAlpha(0f);// 透明的隐藏
		Map<String, View> map = new HashMap<String, View>();
		map.put("normal", normalLayout);
		map.put("selected", selectedLayout);
		tabViews.add(map);
		return tabIndicator;
	}

	/**
	 * 设置tab状态选中
	 * @param index
	 */
	private void setTabSelectedState(int index, int tabCount) {
		for (int i = 0; i < tabCount; i++) {
			if (i == index) {
				tabViews.get(i).get("normal").setAlpha(0f);
				tabViews.get(i).get("selected").setAlpha(1f);
			} else {
				tabViews.get(i).get("normal").setAlpha(1f);
				tabViews.get(i).get("selected").setAlpha(0f);
			}
		}
		jazzyPager.setCurrentItem(index, false);// false表示 代码切换 pager
												// 的时候不带scroll动画
	}

	@Override
	protected void onResume() {
		super.onResume();
		setTabSelectedState(tabHost.getCurrentTab(), 4);
	}
	
	private void initJazzyPager(TransitionEffect effect) {
		jazzyPager.setTransitionEffect(effect);
		jazzyPager.setAdapter(new MainAdapter());
		jazzyPager.setPageMargin(30);
		jazzyPager.setFadeEnabled(true);
		jazzyPager.setSlideCallBack(new SlideCallback() {
			@Override
			public void callBack(int position, float positionOffset) {
				Map<String, View> map = tabViews.get(position);
				ViewHelper.setAlpha(map.get("selected"), positionOffset);
				ViewHelper.setAlpha(map.get("normal"), 1 - positionOffset);
			}
		});
		jazzyPager.setOnPageChangeListener(new OnPageChangeListener() {
			@Override
			public void onPageSelected(int position) {
				tabHost.setCurrentTab(position);
			}

			@Override
			public void onPageScrolled(int paramInt1, float paramFloat, int paramInt2) {
			}

			@Override
			public void onPageScrollStateChanged(int paramInt) {
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add("Toggle Fade");
		String[] effects = this.getResources().getStringArray(R.array.jazzy_effects);
		for (String effect : effects)
			menu.add(effect);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getTitle().toString().equals("Toggle Fade")) {
			jazzyPager.setFadeEnabled(!jazzyPager.getFadeEnabled());
		} else {
			TransitionEffect effect = TransitionEffect.valueOf(item.getTitle().toString());
			initJazzyPager(effect);
		}
		return true;
	}

	private class MainAdapter extends PagerAdapter {
		@Override
		public Object instantiateItem(ViewGroup container, final int position) {
			TextView text = new TextView(MainActivity.this);
			text.setGravity(Gravity.CENTER);
			text.setTextSize(30);
			text.setTextColor(Color.WHITE);
			text.setText("Page " + position);
			text.setPadding(30, 30, 30, 30);
			int bg = Color.rgb((int) Math.floor(Math.random() * 128) + 64, (int) Math.floor(Math.random() * 128) + 64, (int) Math.floor(Math.random() * 128) + 64);
			text.setBackgroundColor(bg);
			container.addView(text, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
			jazzyPager.setObjectForPosition(text, position);
			return text;
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object obj) {
			container.removeView(jazzyPager.findViewFromObject(position));
		}

		@Override
		public int getCount() {
			return 4;
		}

		@Override
		public boolean isViewFromObject(View view, Object obj) {
			if (view instanceof OutlineContainer) {
				return ((OutlineContainer) view).getChildAt(0) == obj;
			} else {
				return view == obj;
			}
		}
	}

}


成员变量:

@ViewInject(R.id.jazzyPager)

private JazzyViewPager jazzyPager; 这里采用了注解来初始化view,[xUtils的功能,以后再也不用写findviewbyid了]

List<Map<String, View>> tabViews 是给pagerAdapter提供资源的

oncreate方法:
ViewUtils.inject(this);//必须在setContentView(R.layout.activity_main);之后就调用,否则可能会出现上面注解初始化失败,导致nullpointexcepter异常

接下来的

tabHost = (TabHost) findViewById(android.R.id.tabhost);
		tabHost.setup();
		tabHost.addTab(tabHost.newTabSpec("0").setIndicator(createTab("主页", 0)).setContent(android.R.id.tabcontent));
		tabHost.addTab(tabHost.newTabSpec("1").setIndicator(createTab("统计", 1)).setContent(android.R.id.tabcontent));
		tabHost.addTab(tabHost.newTabSpec("2").setIndicator(createTab("消息", 2)).setContent(android.R.id.tabcontent));
		tabHost.addTab(tabHost.newTabSpec("3").setIndicator(createTab("设置", 3)).setContent(android.R.id.tabcontent));
		// 点击tabHost 来切换不同的消息
		tabHost.setOnTabChangedListener(new OnTabChangeListener() {
			@Override
			public void onTabChanged(String tabId) {
				int index = Integer.parseInt(tabId);
				setTabSelectedState(index, 4);
				tabHost.getTabContentView().setVisibility(View.GONE);// 隐藏content
			}
		});
		tabHost.setCurrentTab(0);
		initJazzyPager(TransitionEffect.Standard);
添加tab的时候,


setContent有三个,我们用第一个【第三个没用过不知道,第二个是以前用activitygroup的时候用的现在不需要】,参数设置为前面xml中隐藏掉的fragmentlayout,它的id是用的系统提供的id,注意引用方式androud.R.id.tabcontent

这里有个方法setTabSelectedState(int,int) 的作用是设置tab的显示状态为选中状态[我们约定normalLayout未选中,selectedLayout选中][两者的显示/隐藏不通过setVisiblty来设置,而是通过setAlpha来控制吗,以便达到我们要的渐变效果]

/**
	 * 设置tab状态选中
	 * @param index
	 */
	private void setTabSelectedState(int index, int tabCount) {
		for (int i = 0; i < tabCount; i++) {
			if (i == index) {
				tabViews.get(i).get("normal").setAlpha(0f);
				tabViews.get(i).get("selected").setAlpha(1f);
			} else {
				tabViews.get(i).get("normal").setAlpha(1f);
				tabViews.get(i).get("selected").setAlpha(0f);
			}
		}
		jazzyPager.setCurrentItem(index, false);// false表示 代码切换 pager 的时候不带scroll动画
	}
注意:代码切换pager的时候如果传入了第二个参数的话,true代表有切换动画,false代表取消切换动画

接下来在初始化tabhoust后调用一下设置currentTab为0

然后是初始化JazzyPager 默认是用标准动画,就是普通的左右滑动

重点在:

jazzyPager.setPageMargin(30);
		jazzyPager.setFadeEnabled(true);
		jazzyPager.setSlideCallBack(new SlideCallback() {
			@Override
			public void callBack(int position, float positionOffset) {
				Map<String, View> map = tabViews.get(position);
				ViewHelper.setAlpha(map.get("selected"), positionOffset);
				ViewHelper.setAlpha(map.get("normal"), 1 - positionOffset);
			}
		});
		jazzyPager.setOnPageChangeListener(new OnPageChangeListener() {
			@Override
			public void onPageSelected(int position) {
				tabHost.setCurrentTab(position);
			}

			@Override
			public void onPageScrolled(int paramInt1, float paramFloat, int paramInt2) {
			}

			@Override
			public void onPageScrollStateChanged(int paramInt) {
			}
		});


重点来了:

还记得上面的修改的animateFade方法么

回调函数中通过jazzyviewpager的animateFade方法内调用回调函数传递过来的position去获取tabView,然后设置对应的normalLayout和selectedLayout的alpha值即可

pagerAdapter内给每个页面构造了一个文本框,没啥说的,看看代码就懂了,这里就不说了

代码:

@Override
	protected void onResume() {
		super.onResume();
		setTabSelectedState(tabHost.getCurrentTab(), 4);
	}
当页面滑动的过程中回到桌面后再进入APP,底部的tab会出现文章开头的第二幅图的样纸,有一个tab还是半隐的状态,onResume中加上上面的一行可以解决

onCreateOptionsMenu 和onOptionsItemSelected 是切换JazzyViewPager页面的滑动动画的菜单。没啥好说的,看看就懂

-----------------------------------------------------------------------------------------------------------------------------------------------------------

就这么点代码实现了微信6.0的滑动渐变效果有木有啊?~~喀喀喀 ^_^ ~~~

源代码打包[点我下载]

我的资源列表



转载请注明出处:/article/2033402.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: