Android翻页效果原理实现之曲线的实现

尊重原创转载请注明:From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 侵权必究!

炮兵镇楼

上一节我们通过引入折线实现了页面的折叠翻转效果,有了前面两节的基础呢其实曲线的实现可以变得非常简单,为什么这么说呢?因为曲线无非就是在折线的基础上对Path加入了曲线的实现,进而只是影响了我们的Region区域,而其他的什么事件啊、滑动计算啊之类的几乎都是不变的对吧,说白了就是对现有的折线View进行update改造,虽然是改造,但是我们该如何下手呢?首先我们来看看现实中翻页的效果应该是怎样的呢?如果大家身边有书或本子甚至一张纸也行,尝试以不同的方式去翻动它,你会发现除了我们前面两节曾提到过的一些限制外,还有一些special的现象:

一、翻起来的区域从侧面来看是一个有弧度的区域,如图所示侧面图:

而我们将按照第一节中的约定忽略这部分弧度的表现,因为从正俯视的角度我们压根看不到弧度的效果,So~我们强制让其与页面平行:

二、根据拖拽点距离页面高度的不同,我们可以得到不同的卷曲度:

而其在我们正俯视点的表现则是曲线的弧度不同:

同样的,我们按照第一节的约定,为了简化问题,我们将拖拽点距离页面的高度视为一个定值使在我们正俯视点表现的曲线起点从距离控件交点1/4处开始:

三、如上一节末所说,在弯曲的区域图像也会有相似的扭曲效果

OK,大致的一个分析就是这样,我们根据分析结果可以得出下面的一个分析图:

由上图配合我们上面的分析我们可知:DB = 1/4OB,FA = 1/4OA,而点F和点D分别为两条曲线(如无特殊声明,我们所说的曲线均为贝赛尔曲线,下同)的起点(当然你也可以说是终点无所谓),这时,我们以点A、B为曲线的控制点并以其为端点分别沿着x轴和y轴方向作线段AG、BC,另AG = AF、BC = BD,并令点G、C分别为曲线的终点,这样,我们的这两条二阶贝塞尔曲线就非常非常的特殊,例如上图中的曲线DC,它是由起始点D、C和控制点B构成,而BD = BC,也就是说三角形BDC是的等腰三角形,进一步地说就是曲线DC的两条控制杆力臂相等,进一步地我们可以推断出曲线DC的顶点J必定在直线DC的中垂线上,更进一步地我们可以根据《自定义控件其实很简单5/12》所说的二阶贝塞尔曲线公式得出当且仅当t
= 0.5时曲线的端点刚好会在顶点J上,由此我们可以非常非常简单地得到曲线的顶点坐标。好了,YY归YY我们还是要回归到具体的操作中来,首先,我们要计算出点G、F、D、C的坐标值,这四点坐标也相当easy,就拿F点坐标来说,我们过点F分别作OM、AM的垂线:

因为FA = 1/4OA,那么我们可以得到F点的x坐标Fx = a + 3/4MA,y坐标Fy = b + 3/4OM,而G点的x坐标Gx = a + MA - 1/4x;其他两点D、C就不多扯了,那么在代码中如何体现呢?首先,为了便于观察效果,我们先注释掉图片的绘制:

/*
 * 如果坐标点在原点(即还没发生触碰时)则绘制第一页
 */
if (mPointX == 0 && mPointY == 0) {
	// canvas.drawBitmap(mBitmaps.get(mBitmaps.size() - 1), 0, 0, null);
	return;
}

// 省略大量代码

//drawBitmaps(canvas);

并绘制线条:

canvas.drawPath(mPath, mPaint);

在上一节中我们在生成Path时将情况分为了两种:

if (sizeLong > mViewHeight) {
	//…………………………
} else {
	//…………………………
}

同样,我们也分开处理两种情况,那么针对sizeLong > mViewHeight的时候此时控件顶部的曲线效果已经是看不到了,我们只需考虑底部的曲线效果:

// 计算曲线起点
float startXBtm = btmX2 - CURVATURE * sizeShort;
float startYBtm = mViewHeight;

// 计算曲线终点
float endXBtm = mPointX + (1 - CURVATURE) * (tempAM);
float endYBtm = mPointY + (1 - CURVATURE) * mL;

// 计算曲线控制点
float controlXBtm = btmX2;
float controlYBtm = mViewHeight;

// 计算曲线顶点
float bezierPeakXBtm = 0.25F * startXBtm + 0.5F * controlXBtm + 0.25F * endXBtm;
float bezierPeakYBtm = 0.25F * startYBtm + 0.5F * controlYBtm + 0.25F * endYBtm;

/*
 * 生成带曲线的四边形路径
 */
mPath.moveTo(startXBtm, startYBtm);
mPath.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPath.lineTo(mPointX, mPointY);
mPath.lineTo(topX1, 0);
mPath.lineTo(topX2, 0);
mPath.lineTo(bezierPeakXBtm, bezierPeakYBtm);

该部分的实际效果如下:

PS:为了便于大家对参数的理解,我对每一个点的坐标都重新给予了一个引用其命名也浅显易懂,实际过程可以省略这一步简化代码

而当sizeLong <= mViewHeight时这时候不但底部有曲线效果,右侧也有:

/*
 * 计算参数
 */
float leftY = mViewHeight - sizeLong;
float btmX = mViewWidth - sizeShort;

// 计算曲线起点
float startXBtm = btmX - CURVATURE * sizeShort;
float startYBtm = mViewHeight;
float startXLeft = mViewWidth;
float startYLeft = leftY - CURVATURE * sizeLong;

/*
 * 限制左侧曲线起点
 */
if (startYLeft <= 0) {
	startYLeft = 0;
}

/*
 * 限制右侧曲线起点
 */
if (startXBtm <= 0) {
	startXBtm = 0;
}

// 计算曲线终点
float endXBtm = mPointX + (1 - CURVATURE) * (tempAM);
float endYBtm = mPointY + (1 - CURVATURE) * mL;
float endXLeft = mPointX + (1 - CURVATURE) * mK;
float endYLeft = mPointY - (1 - CURVATURE) * (sizeLong - mL);

// 计算曲线控制点
float controlXBtm = btmX;
float controlYBtm = mViewHeight;
float controlXLeft = mViewWidth;
float controlYLeft = leftY;

// 计算曲线顶点
float bezierPeakXBtm = 0.25F * startXBtm + 0.5F * controlXBtm + 0.25F * endXBtm;
float bezierPeakYBtm = 0.25F * startYBtm + 0.5F * controlYBtm + 0.25F * endYBtm;
float bezierPeakXLeft = 0.25F * startXLeft + 0.5F * controlXLeft + 0.25F * endXLeft;
float bezierPeakYLeft = 0.25F * startYLeft + 0.5F * controlYLeft + 0.25F * endYLeft;

/*
 * 生成带曲线的三角形路径
 */
mPath.moveTo(startXBtm, startYBtm);
mPath.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPath.lineTo(mPointX, mPointY);
mPath.lineTo(endXLeft, endYLeft);
mPath.quadTo(controlXLeft, controlYLeft, startXLeft, startYLeft);

效果如下:

Path有了,我们就该考虑如何将其转换为Region,在这个过程中呢又一个问题,曲线路径不像上一节的直线路径我们可以轻易获得其范围区域,因为我们的折叠区域其实应该是这样的:

如图所示红色路径区域,这部分区域则是我们折叠的区域,而事实上我们为了计算方便将整条二阶贝赛尔曲线都绘制了出来,也就是说我们的Path除了红色线条部分还包含了蓝色线条部分对吧,那么问题来了,如何将这两部分“做掉”呢?其实方法很多,我们可以在计算的时候就只生成半条曲线,这是方法一我们利用纯计算的方式,记得我在该系列文章开头曾说过翻页效果的实现可以有两种方式,一种是纯计算而另一种则是利用图形的组合思想,如何组合呢?这里对于区域的计算我们就不用纯计算的方式了,我们尝试用图形组合来试试。首先我们将Path转为Region看看是什么样的:

Region region = computeRegion(mPath);
canvas.clipRegion(region);
canvas.drawColor(Color.RED);
// canvas.drawPath(mPath, mPaint);

效果如下:

可以看到我们没有封闭的Path形成的Region效果,事实呢跟我们需要的区域差距有点大,首先上下两个月半圆是多余的,其次目测少了一块对吧:

如上图蓝色的那块,那么我们该如何把这块“补”回来呢?利用图形组合的思想,我们设法为该Region补一块矩形:

然后差集掉两个月半圆不就成了?这部分代码改动较大,我先贴代码再说吧:

if (sizeLong > mViewHeight) {
	// 计算……额……按图来AN边~
	float an = sizeLong - mViewHeight;

	// 三角形AMN的MN边
	float largerTrianShortSize = an / (sizeLong - (mViewHeight - mPointY)) * (mViewWidth - mPointX);

	// 三角形AQN的QN边
	float smallTrianShortSize = an / sizeLong * sizeShort;

	/*
	 * 计算参数
	 */
	float topX1 = mViewWidth - largerTrianShortSize;
	float topX2 = mViewWidth - smallTrianShortSize;
	float btmX2 = mViewWidth - sizeShort;

	// 计算曲线起点
	float startXBtm = btmX2 - CURVATURE * sizeShort;
	float startYBtm = mViewHeight;

	// 计算曲线终点
	float endXBtm = mPointX + (1 - CURVATURE) * (tempAM);
	float endYBtm = mPointY + (1 - CURVATURE) * mL;

	// 计算曲线控制点
	float controlXBtm = btmX2;
	float controlYBtm = mViewHeight;

	// 计算曲线顶点
	float bezierPeakXBtm = 0.25F * startXBtm + 0.5F * controlXBtm + 0.25F * endXBtm;
	float bezierPeakYBtm = 0.25F * startYBtm + 0.5F * controlYBtm + 0.25F * endYBtm;

	/*
	 * 生成带曲线的四边形路径
	 */
	mPath.moveTo(startXBtm, startYBtm);
	mPath.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
	mPath.lineTo(mPointX, mPointY);
	mPath.lineTo(topX1, 0);
	mPath.lineTo(topX2, 0);

	/*
	 * 替补区域Path
	 */
	mPathTrap.moveTo(startXBtm, startYBtm);
	mPathTrap.lineTo(topX2, 0);
	mPathTrap.lineTo(bezierPeakXBtm, bezierPeakYBtm);
	mPathTrap.close();

	/*
	 * 底部月半圆Path
	 */
	mPathSemicircleBtm.moveTo(startXBtm, startYBtm);
	mPathSemicircleBtm.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
	mPathSemicircleBtm.close();

	/*
	 * 生成包含折叠和下一页的路径
	 */
	//暂时没用省略掉

	// 计算月半圆区域
	mRegionSemicircle = computeRegion(mPathSemicircleBtm);
} else {
	/*
	 * 计算参数
	 */
	float leftY = mViewHeight - sizeLong;
	float btmX = mViewWidth - sizeShort;

	// 计算曲线起点
	float startXBtm = btmX - CURVATURE * sizeShort;
	float startYBtm = mViewHeight;
	float startXLeft = mViewWidth;
	float startYLeft = leftY - CURVATURE * sizeLong;

	// 计算曲线终点
	float endXBtm = mPointX + (1 - CURVATURE) * (tempAM);
	float endYBtm = mPointY + (1 - CURVATURE) * mL;
	float endXLeft = mPointX + (1 - CURVATURE) * mK;
	float endYLeft = mPointY - (1 - CURVATURE) * (sizeLong - mL);

	// 计算曲线控制点
	float controlXBtm = btmX;
	float controlYBtm = mViewHeight;
	float controlXLeft = mViewWidth;
	float controlYLeft = leftY;

	// 计算曲线顶点
	float bezierPeakXBtm = 0.25F * startXBtm + 0.5F * controlXBtm + 0.25F * endXBtm;
	float bezierPeakYBtm = 0.25F * startYBtm + 0.5F * controlYBtm + 0.25F * endYBtm;
	float bezierPeakXLeft = 0.25F * startXLeft + 0.5F * controlXLeft + 0.25F * endXLeft;
	float bezierPeakYLeft = 0.25F * startYLeft + 0.5F * controlYLeft + 0.25F * endYLeft;

	/*
	 * 限制右侧曲线起点
	 */
	if (startYLeft <= 0) {
		startYLeft = 0;
	}

	/*
	 * 限制底部左侧曲线起点
	 */
	if (startXBtm <= 0) {
		startXBtm = 0;
	}

	/*
	 * 根据底部左侧限制点重新计算贝塞尔曲线顶点坐标
	 */
	float partOfShortLength = CURVATURE * sizeShort;
	if (btmX >= -mValueAdded && btmX <= partOfShortLength - mValueAdded) {
		float f = btmX / partOfShortLength;
		float t = 0.5F * f;

		float bezierPeakTemp = 1 - t;
		float bezierPeakTemp1 = bezierPeakTemp * bezierPeakTemp;
		float bezierPeakTemp2 = 2 * t * bezierPeakTemp;
		float bezierPeakTemp3 = t * t;

		bezierPeakXBtm = bezierPeakTemp1 * startXBtm + bezierPeakTemp2 * controlXBtm + bezierPeakTemp3 * endXBtm;
		bezierPeakYBtm = bezierPeakTemp1 * startYBtm + bezierPeakTemp2 * controlYBtm + bezierPeakTemp3 * endYBtm;
	}

	/*
	 * 根据右侧限制点重新计算贝塞尔曲线顶点坐标
	 */
	float partOfLongLength = CURVATURE * sizeLong;
	if (leftY >= -mValueAdded && leftY <= partOfLongLength - mValueAdded) {
		float f = leftY / partOfLongLength;
		float t = 0.5F * f;

		float bezierPeakTemp = 1 - t;
		float bezierPeakTemp1 = bezierPeakTemp * bezierPeakTemp;
		float bezierPeakTemp2 = 2 * t * bezierPeakTemp;
		float bezierPeakTemp3 = t * t;

		bezierPeakXLeft = bezierPeakTemp1 * startXLeft + bezierPeakTemp2 * controlXLeft + bezierPeakTemp3 * endXLeft;
		bezierPeakYLeft = bezierPeakTemp1 * startYLeft + bezierPeakTemp2 * controlYLeft + bezierPeakTemp3 * endYLeft;
	}

	/*
	 * 替补区域Path
	 */
	mPathTrap.moveTo(startXBtm, startYBtm);
	mPathTrap.lineTo(startXLeft, startYLeft);
	mPathTrap.lineTo(bezierPeakXLeft, bezierPeakYLeft);
	mPathTrap.lineTo(bezierPeakXBtm, bezierPeakYBtm);
	mPathTrap.close();

	/*
	 * 生成带曲线的三角形路径
	 */
	mPath.moveTo(startXBtm, startYBtm);
	mPath.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
	mPath.lineTo(mPointX, mPointY);
	mPath.lineTo(endXLeft, endYLeft);
	mPath.quadTo(controlXLeft, controlYLeft, startXLeft, startYLeft);

	/*
	 * 生成底部月半圆的Path
	 */
	mPathSemicircleBtm.moveTo(startXBtm, startYBtm);
	mPathSemicircleBtm.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
	mPathSemicircleBtm.close();

	/*
	 * 生成右侧月半圆的Path
	 */
	mPathSemicircleLeft.moveTo(endXLeft, endYLeft);
	mPathSemicircleLeft.quadTo(controlXLeft, controlYLeft, startXLeft, startYLeft);
	mPathSemicircleLeft.close();

	/*
	 * 生成包含折叠和下一页的路径
	 */
	//暂时没用省略掉

	/*
	 * 计算底部和右侧两月半圆区域
	 */
	Region regionSemicircleBtm = computeRegion(mPathSemicircleBtm);
	Region regionSemicircleLeft = computeRegion(mPathSemicircleLeft);

	// 合并两月半圆区域
	mRegionSemicircle.op(regionSemicircleBtm, regionSemicircleLeft, Region.Op.UNION);
}

// 根据Path生成的折叠区域
Region regioFlod = computeRegion(mPath);

// 替补区域
Region regionTrap = computeRegion(mPathTrap);

// 令折叠区域与替补区域相加
regioFlod.op(regionTrap, Region.Op.UNION);

// 从相加后的区域中剔除掉月半圆的区域获得最终折叠区域
regioFlod.op(mRegionSemicircle, Region.Op.DIFFERENCE);

/*
 * 根据裁剪区域填充画布
 */
canvas.clipRegion(regioFlod);
canvas.drawColor(Color.RED);

200行的代码我们就做了一件事就是正确计算Path,同样我们还是按照之前的分了两种情况来计算,第一种情况sizeLong > mViewHeight时,我们先计算替补的这块区域:

如上代码46-49行

/*
 * 替补区域Path
 */
mPathTrap.moveTo(startXBtm, startYBtm);
mPathTrap.lineTo(topX2, 0);
mPathTrap.lineTo(bezierPeakXBtm, bezierPeakYBtm);
mPathTrap.close();

然后计算底部的月半圆Path:

对应代码54-56行

/*
 * 底部月半圆Path
 */
mPathSemicircleBtm.moveTo(startXBtm, startYBtm);
mPathSemicircleBtm.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPathSemicircleBtm.close();

将当前折叠区域和替补区域相加再减去月半圆Path区域我们就可以得到正确的折叠区域,对应代码64行和192-201行:

// 计算月半圆区域
mRegionSemicircle = computeRegion(mPathSemicircleBtm);

// ………………中间省略巨量代码………………

// 根据Path生成的折叠区域
Region regioFlod = computeRegion(mPath);

// 替补区域
Region regionTrap = computeRegion(mPathTrap);

// 令折叠区域与替补区域相加
regioFlod.op(regionTrap, Region.Op.UNION);

// 从相加后的区域中剔除掉月半圆的区域获得最终折叠区域
regioFlod.op(mRegionSemicircle, Region.Op.DIFFERENCE);

该情况下我们的折叠区域是酱紫的:

两一种情况则稍微复杂些,除了要计算底部,我们还要计算右侧的月半圆Path区域,代码165-174:

/*
 * 生成底部月半圆的Path
 */
mPathSemicircleBtm.moveTo(startXBtm, startYBtm);
mPathSemicircleBtm.quadTo(controlXBtm, controlYBtm, endXBtm, endYBtm);
mPathSemicircleBtm.close();

/*
 * 生成右侧月半圆的Path
 */
mPathSemicircleLeft.moveTo(endXLeft, endYLeft);
mPathSemicircleLeft.quadTo(controlXLeft, controlYLeft, startXLeft, startYLeft);
mPathSemicircleLeft.close();
替补区域的计算,147-151:
/*
 * 替补区域Path
 */
mPathTrap.moveTo(startXBtm, startYBtm);
mPathTrap.lineTo(startXLeft, startYLeft);
mPathTrap.lineTo(bezierPeakXLeft, bezierPeakYLeft);
mPathTrap.lineTo(bezierPeakXBtm, bezierPeakYBtm);
mPathTrap.close();
区域的转换,184-188:
/*
 * 计算底部和右侧两月半圆区域
 */
Region regionSemicircleBtm = computeRegion(mPathSemicircleBtm);
Region regionSemicircleLeft = computeRegion(mPathSemicircleLeft);

// 合并两月半圆区域
mRegionSemicircle.op(regionSemicircleBtm, regionSemicircleLeft, Region.Op.UNION);

最终的计算跟上面第一种情况一样,效果如下:

结合两种情况,我们可以得到下面的效果:

然后,我们需要计算“下一页”的区域,同样,根据上一节我们的讲解,我们先获取折叠区域和下一页区域之和再减去折叠区域就可以得到下一页的区域:

mRegionNext = computeRegion(mPathFoldAndNext);
mRegionNext.op(mRegionFold, Region.Op.DIFFERENCE);

绘制效果如下:

最后,我们结合上两节,注入数据:

/**
 * 绘制位图数据
 *
 * @param canvas
 *            画布对象
 */
private void drawBitmaps(Canvas canvas) {
	// 绘制位图前重置isLastPage为false
	isLastPage = false;

	// 限制pageIndex的值范围
	mPageIndex = mPageIndex < 0 ? 0 : mPageIndex;
	mPageIndex = mPageIndex > mBitmaps.size() ? mBitmaps.size() : mPageIndex;

	// 计算数据起始位置
	int start = mBitmaps.size() - 2 - mPageIndex;
	int end = mBitmaps.size() - mPageIndex;

	/*
	 * 如果数据起点位置小于0则表示当前已经到了最后一张图片
	 */
	if (start < 0) {
		// 此时设置isLastPage为true
		isLastPage = true;

		// 并显示提示信息
		showToast("This is fucking lastest page");

		// 强制重置起始位置
		start = 0;
		end = 1;
	}

	/*
	 * 计算当前页的区域
	 */
	canvas.save();
	canvas.clipRegion(mRegionCurrent);
	canvas.drawBitmap(mBitmaps.get(end - 1), 0, 0, null);
	canvas.restore();

	/*
	 * 计算折叠页的区域
	 */
	canvas.save();
	canvas.clipRegion(mRegionFold);

	canvas.translate(mPointX, mPointY);

	/*
	 * 根据长短边标识计算折叠区域图像
	 */
	if (mRatio == Ratio.SHORT) {
		canvas.rotate(90 - mDegrees);
		canvas.translate(0, -mViewHeight);
		canvas.scale(-1, 1);
		canvas.translate(-mViewWidth, 0);
	} else {
		canvas.rotate(-(90 - mDegrees));
		canvas.translate(-mViewWidth, 0);
		canvas.scale(1, -1);
		canvas.translate(0, -mViewHeight);
	}

	canvas.drawBitmap(mBitmaps.get(end - 1), 0, 0, null);
	canvas.restore();

	/*
	 * 计算下一页的区域
	 */
	canvas.save();
	canvas.clipRegion(mRegionNext);
	canvas.drawBitmap(mBitmaps.get(start), 0, 0, null);
	canvas.restore();
}

最终效果如下:

该部分的代码就不贴出了,大部分跟上一节相同,因为过两天要去旅游时间略紧这节略讲得粗糙,不过也没什么太大的改动,如果大家有不懂的地方可以留言或群里@哥,下一节我们将尝试实现翻页时图像扭曲的效果。

源码地址:传送门

时间: 2024-10-12 05:59:19

Android翻页效果原理实现之曲线的实现的相关文章

Android翻页效果原理实现之翻页的尝试

尊重原创转载请注明:From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 侵权必究! 炮兵镇楼 在<自定义控件其实很简单>系列的前半部分中我们用了整整六节近两万字两百多张配图讲了Android图形的绘制,虽然篇幅很巨大但仍然只是图形绘制的冰山一角,旨在领大家入门,至于修行成果就看各位的了--那么这个些列主要是通过前面学习到的一些方法来尝试完成一个翻页的效果. 对于我个人来说,我是不太建议大家在没自己去尝试前看本文的,因为你看

Android翻页效果原理实现之模拟扭曲

尊重原创转载请注明:From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 侵权必究! 炮兵镇楼 上一节我们实现了翻页的曲线效果,但是效果有点小瑕疵不知道大家发现没有: 如图,我们发现折叠区域怪怪的,并没有实现我们之前的"弯曲"效果,为什么呢?是计算错了么?其实不是的,我们之前测试的时候使用的将canvas填色,但是这里我们用到的是一张位图,虽然我们的Path是曲线.Region有曲线区域,但是我们的Bitmap是个规

Android 实现书籍翻页效果(转载链接)

Android 实现书籍翻页效果----原理篇 效果图: Android 实现书籍翻页效果----完结篇 效果图: Android 实现书籍翻页效果----升级篇 效果图: Android 实现书籍翻页效果---番外篇之光影效果

android开发教程:android手势翻页效果

听麦子学院android开发老师说要实现手势翻页效果,主要用到ViewFlipper和GestureDetector.  ViewFlipper变化当前显示内容,GestureDetector监听手势.  用于多页的展示非常酷.  现在我就给大家简单说明下,  首先创建工程:TestFlip,创建主Activity:TestFlip.  在res/layout/main.xml中添加flipper信息,如下:  Java代码   1. <?xml version="1.0" en

Android用悬浮按钮实现翻页效果

今天给大家分享下自己用悬浮按钮点击实现翻页效果的例子. 首先,一个按钮要实现悬浮,就要用到系统顶级窗口相关的WindowManager,WindowManager.LayoutParams.那么在AndroidManifest.xml中添加权限: ? 1 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 然后,我们要对WindowManager,WindowManager.La

Android应用源码之双面翻页效果

Android应用源码之双面翻页效果 在网上看到一个非常不错的源码,想跟大家分享一下.仔细翻了翻源码是实现翻页效果的,有兴趣的朋友可以研究一下! 下载地址:http://www.devstore.cn/code/info/804.html 运行截图:   

android之实现上下左右翻页效果

如果实现上下或者左右翻页效果,我们借助下这个开源项目:https://github.com/openaphid/android-flip Aphid FlipView是一个能够实现Flipboard翻页效果的UI组件. 下载完毕后导入到当前你的项目中,我们来下上下翻页的效果图:           直接贴出代码: 布局文件: <span style="font-size:14px;"><?xml version="1.0" encoding=&qu

前端实现类似于iBooks的图书翻页效果的网络阅读软件(一)

昨天晚上在群里交流各种脑动大开的题目,我顺手也提了一个问题: JS如何做“字符分页“ 原意是源于我4年前公司项目,我负责开发1年的样子,后来各种原因就没有然后了… http://reader.appcarrier.com/     以上图片是手机上的截图,Metro风格当前可是风靡一时,软件本身是类似现在的”追书神器” 通过书名,在网络上搜索到对应的内容,之后保存到本地数据库.在通过JS获取数据再处理 自己装好测了下,貌似下载服务器已经挂了~ 程序采用PhoneGap打包的,数据采集是用底层完成

FlipViewPager 对item实现左右对折滑动翻页效果《IT蓝豹》

FlipViewPager 对item实现左右对折滑动翻页效果 <FlipViewPager 对每一条item实现左右对折滑动翻页效果>,解决左右滑动和上下滑动的事件分发处理机制.内部实现如下:用ListView试下,对listview设置adapter,这个adapter继承BaseFlipAdapter<Friend>,然后对每一个item进行view处理,部分代码如下:class FriendsAdapter extends BaseFlipAdapter<Friend