在过滤后的图像之间滑动 android
Swipe between filtered images for android
本质上,我是在重新询问 this question 但为了在 android 上实施它。
I am trying to allow users to swipe between filters on a static image.
The idea is that the image stays in place while the filter scrolls
above it. Snapchat recently released a version which implements this
feature. This video shows exactly what I'm trying to accomplish at
1:05.
我尝试用叠加层填充列表并使用 onFling 对其进行分页并使用 onDraw 进行绘图,但我丢失了动画。有没有办法用 ViewPager 做到这一点?
编辑:根据要求,我提供了覆盖视图分页的实现。它用位于图像视图顶部的透明 png 图像填充 viewpager。此外,此代码在 C# 中,因为我使用的是 Xamarin Android。对于不熟悉 C#
的人来说,它与 Java 非常相似
...
static List<ImageView> overlayList = new List<ImageView>();
...
public class OverlayFragmentAdapter : FragmentPagerAdapter
{
public OverlayFragmentAdapter(Android.Support.V4.App.FragmentManager fm) : base(fm)
{
}
public override int Count
{
get { return 5; } //hardcoded temporarily
}
public override Android.Support.V4.App.Fragment GetItem(int position)
{
return new OverlayFragment ();
}
}
public class OverlayFragment : Android.Support.V4.App.Fragment
{
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.Inflate (Resource.Layout.fragment_overlay, container, false);
LinearLayout l1 = view.FindViewById<LinearLayout> (Resource.Id.overlay_container);
ImageView im = new ImageView (Activity);
im.SetImageResource (Resource.Drawable.Overlay); //Resource.Drawable.Overlay is a simple png transparency I created. R
l1.AddView (im);
overlayList.AddElement (im);
return view;
}
}
Activity布局XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="bottom">
<ImageView
android:id="@+id/background_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout <!-- This second layout is for buttons which I have omitted from this code -->
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/edit_layout">
<android.support.v4.view.ViewPager
android:id="@+id/overlay_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
</RelativeLayout>
片段叠加XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/overlay_container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center" />
简要总结一下:viewpager 位于第一个 imageview 的顶部,它充当背景。 OnCreateView 方法从资源创建覆盖片段和覆盖图像视图,并将其放入 overlay_container 布局中。保存图像(我没有发布,因为它超出了这个问题的范围)很简单,它所做的就是创建一个背景位图,一个叠加位图,并使用 canvas 将叠加层绘制到背景上,然后写入文件。
对于这个应用程序,我觉得使用 android 动画功能并将动画值设置为您想要的过滤器是最容易的。因此,您可以制作自己的动画,即更改后的过滤器遍历您的数组。
我自己也做过类似的事情。
对于您的特定用例,我只使用 canvas 和 alpha 混合滤镜,作为顶部图像。
要进行 alpha 混合,将第一个图像(原始图像)的 alpha 绘画设置为 255,将第二个图像(滤镜)的 alpha 设置为 128 之类的东西。
您只需要一个具有图像大小的滤镜,然后在绘制时移动第二个图像的位置。就是这样。
速度极快,可以在非常非常旧的设备上使用。
这是一个示例实现:
Bitmap filter, // the filter
original, // our original
tempBitmap; // the bitmap which holds the canvas results
// and is then drawn to the imageView
Canvas mCanvas; // our canvas
int x = 0; // The x coordinate of the filter. This variable will be manipulated
// in either onFling or onScroll.
void draw() {
// clear canvas
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// setup paint
paint0.setAlpha(255); // the original needs to be fully visible
paint1.setAlpha(128); // the filter should be alpha blended into the original.
// enable AA for paint
// filter image
paint1.setAntiAlias(true);
paint1.setFlags(Paint.ANTI_ALIAS_FLAG); // Apply AA to the image. Optional.
paint1.setFlags(Paint.FILTER_BITMAP_FLAG); // In case you scale your image, apple
// bilinear filtering. Optional.
// original image
paint0.setAntiAlias(true);
paint0.setFlags(Paint.ANTI_ALIAS_FLAG);
paint0.setFlags(Paint.FILTER_BITMAP_FLAG);
// draw onto the canvas
mCanvas.save();
mCanvas.drawBitmap(original, 0,0,paint0);
mCanvas.drawBitmap(filter, x,0,paint1);
mCanvas.restore();
// set the new image
imageView.setImageDrawable(new BitmapDrawable(getResources(), tempBitmap));
}
这里是基本的 onFling
and onScroll
实现。
private static final int SWIPE_DISTANCE_THRESHOLD = 125;
private static final int SWIPE_VELOCITY_THRESHOLD = 75;
// make sure to have implemented GestureDetector.OnGestureListener for these to work.
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
float distanceX = e2.getX() - e1.getX();
float distanceY = e2.getY() - e1.getY();
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) >
SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
// change picture to
if (distanceX > 0) {
// start left increment
}
else { // the left
// start right increment
}
}
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// checks if we're touching for more than 2f. I like to have this implemented, to prevent
// jerky image motion, when not really moving my finger, but still touching. Optional.
if (Math.abs(distanceY) > 2 || Math.abs(distanceX) > 2) {
if(Math.abs(distanceX) > Math.abs(distanceY)) {
// move the filter left or right
}
}
}
注意:onScroll/onFling 实现具有 x 调整的伪代码,因为这些功能需要测试。将来最终实现此功能的人可以随时编辑答案并提供这些功能。
查看默认日历应用 onDraw
方法的实现:DayView。
有onFling
根据动作变化实现重绘内容(如日历网格),仿fling。
然后就可以根据动作的变化在onDraw
中使用ColorFilter了。速度非常快。
或者,您可以将 ViewSwitcher 与过滤图像列表一起使用(或以某种方式创建过滤图像缓存)。要实现"drawing over the image"的可能性,可以在RelativeLayout
中使用ImageView
和ViewSwitcher
一个在上面,在ImageView
结束后设置新的过滤图像滚动。
本质上,我是在重新询问 this question 但为了在 android 上实施它。
I am trying to allow users to swipe between filters on a static image. The idea is that the image stays in place while the filter scrolls above it. Snapchat recently released a version which implements this feature. This video shows exactly what I'm trying to accomplish at 1:05.
我尝试用叠加层填充列表并使用 onFling 对其进行分页并使用 onDraw 进行绘图,但我丢失了动画。有没有办法用 ViewPager 做到这一点?
编辑:根据要求,我提供了覆盖视图分页的实现。它用位于图像视图顶部的透明 png 图像填充 viewpager。此外,此代码在 C# 中,因为我使用的是 Xamarin Android。对于不熟悉 C#
的人来说,它与 Java 非常相似...
static List<ImageView> overlayList = new List<ImageView>();
...
public class OverlayFragmentAdapter : FragmentPagerAdapter
{
public OverlayFragmentAdapter(Android.Support.V4.App.FragmentManager fm) : base(fm)
{
}
public override int Count
{
get { return 5; } //hardcoded temporarily
}
public override Android.Support.V4.App.Fragment GetItem(int position)
{
return new OverlayFragment ();
}
}
public class OverlayFragment : Android.Support.V4.App.Fragment
{
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.Inflate (Resource.Layout.fragment_overlay, container, false);
LinearLayout l1 = view.FindViewById<LinearLayout> (Resource.Id.overlay_container);
ImageView im = new ImageView (Activity);
im.SetImageResource (Resource.Drawable.Overlay); //Resource.Drawable.Overlay is a simple png transparency I created. R
l1.AddView (im);
overlayList.AddElement (im);
return view;
}
}
Activity布局XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="bottom">
<ImageView
android:id="@+id/background_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<RelativeLayout <!-- This second layout is for buttons which I have omitted from this code -->
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/edit_layout">
<android.support.v4.view.ViewPager
android:id="@+id/overlay_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
</RelativeLayout>
片段叠加XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/overlay_container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center" />
简要总结一下:viewpager 位于第一个 imageview 的顶部,它充当背景。 OnCreateView 方法从资源创建覆盖片段和覆盖图像视图,并将其放入 overlay_container 布局中。保存图像(我没有发布,因为它超出了这个问题的范围)很简单,它所做的就是创建一个背景位图,一个叠加位图,并使用 canvas 将叠加层绘制到背景上,然后写入文件。
对于这个应用程序,我觉得使用 android 动画功能并将动画值设置为您想要的过滤器是最容易的。因此,您可以制作自己的动画,即更改后的过滤器遍历您的数组。
我自己也做过类似的事情。
对于您的特定用例,我只使用 canvas 和 alpha 混合滤镜,作为顶部图像。
要进行 alpha 混合,将第一个图像(原始图像)的 alpha 绘画设置为 255,将第二个图像(滤镜)的 alpha 设置为 128 之类的东西。
您只需要一个具有图像大小的滤镜,然后在绘制时移动第二个图像的位置。就是这样。
速度极快,可以在非常非常旧的设备上使用。
这是一个示例实现:
Bitmap filter, // the filter
original, // our original
tempBitmap; // the bitmap which holds the canvas results
// and is then drawn to the imageView
Canvas mCanvas; // our canvas
int x = 0; // The x coordinate of the filter. This variable will be manipulated
// in either onFling or onScroll.
void draw() {
// clear canvas
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// setup paint
paint0.setAlpha(255); // the original needs to be fully visible
paint1.setAlpha(128); // the filter should be alpha blended into the original.
// enable AA for paint
// filter image
paint1.setAntiAlias(true);
paint1.setFlags(Paint.ANTI_ALIAS_FLAG); // Apply AA to the image. Optional.
paint1.setFlags(Paint.FILTER_BITMAP_FLAG); // In case you scale your image, apple
// bilinear filtering. Optional.
// original image
paint0.setAntiAlias(true);
paint0.setFlags(Paint.ANTI_ALIAS_FLAG);
paint0.setFlags(Paint.FILTER_BITMAP_FLAG);
// draw onto the canvas
mCanvas.save();
mCanvas.drawBitmap(original, 0,0,paint0);
mCanvas.drawBitmap(filter, x,0,paint1);
mCanvas.restore();
// set the new image
imageView.setImageDrawable(new BitmapDrawable(getResources(), tempBitmap));
}
这里是基本的 onFling
and onScroll
实现。
private static final int SWIPE_DISTANCE_THRESHOLD = 125;
private static final int SWIPE_VELOCITY_THRESHOLD = 75;
// make sure to have implemented GestureDetector.OnGestureListener for these to work.
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
float distanceX = e2.getX() - e1.getX();
float distanceY = e2.getY() - e1.getY();
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) >
SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
// change picture to
if (distanceX > 0) {
// start left increment
}
else { // the left
// start right increment
}
}
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// checks if we're touching for more than 2f. I like to have this implemented, to prevent
// jerky image motion, when not really moving my finger, but still touching. Optional.
if (Math.abs(distanceY) > 2 || Math.abs(distanceX) > 2) {
if(Math.abs(distanceX) > Math.abs(distanceY)) {
// move the filter left or right
}
}
}
注意:onScroll/onFling 实现具有 x 调整的伪代码,因为这些功能需要测试。将来最终实现此功能的人可以随时编辑答案并提供这些功能。
查看默认日历应用 onDraw
方法的实现:DayView。
有onFling
根据动作变化实现重绘内容(如日历网格),仿fling。
然后就可以根据动作的变化在onDraw
中使用ColorFilter了。速度非常快。
或者,您可以将 ViewSwitcher 与过滤图像列表一起使用(或以某种方式创建过滤图像缓存)。要实现"drawing over the image"的可能性,可以在RelativeLayout
中使用ImageView
和ViewSwitcher
一个在上面,在ImageView
结束后设置新的过滤图像滚动。