Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
✓ Live Streaming✓ Interactive Chat✓ Private Shows✓ HD Quality
Anya is LIVE right now
FREE
Free to watch • No registration required • HD streaming
The April Fools 2016 project was executed and finalized on a very tight deadline. The mobile platforms (Android, iOS) had only 2 weeks to ship a finalized, polished implementation from scratch. Originally, we planned on doing a full-blown custom election, where users would, themselves, be able to run as a candidates in the election, create their own campaign and be featured on a top Candidates page. However, we had to scope down the project as much as we could. Development had to occur while scoping the project and mocks were incomplete.
One of the biggest contributors to the success of the AF project were the new creator tools we provided. The campaign posters and campaign endorsements.
While creating the campaign poster creator on Android, there were 4 main actions to implement for users:
1) Adding items to the poster
2) Dragging items
3) Scaling items
4) Rotating items
* "items" refers to text and stickers
I decided to structure the implementation as follows:
image of activity -> layoutView -> canvas, with imageViews and textviews being added to the canvas, and the color picker being a separate ViewGroup.
Adding Text and Stickers
A custom CanvasLayout subclassing FrameLayout was the main drawing board. I added buttons in activity layout with click with the CanvasLayout through CanvasLayout.changeBackgroundTapped(), CanvasLayout.stickerTapped() or CanvasLayout.addTextTapped(). When the user taps the add-text button, CanvasLayout dynamically adds a TextView to the layout.
public void addTextItem() { TextView textView = new TextView(); textView.color = ...; textView.properties = ...; textView.setFocusable(true); }
And similar for stickers, except adding ImageViews with selected drawables to the CanvasLayout view.
Dealing with Touches
Unfortunately, there's no simple way to scale or rotate views on Android. I created a custom AFTextView subclassing TextView and a custom AFStickerView subclassing ImageView. These views intercept touch events and figure out what the user is trying to do. A simple overview of what the logic in onTouch() looked like:
@Override public onTouch(MotionEvent ev) { if (ev == TOUCH_DOWN) { // save the x & y position of the user's touch down! } elseif (ev == TOUCH_UP) { // reset the variables, the user just lifted their finger and doesn't want to do anything } elseif (ev == TOUCH_MOVE) { // we're either dragging, scaling or rotating, figure out which one! } } (For information on each event type, refer to MotionEvent reference docs)
As you can probably tell, the most difficult part is figuring out what to do on ACTION_MOVE. I started off with scaling and dragging. The biggest difference between the two is: you need two fingers for scaling, you need one finger for dragging. So let's keep track of each finger with an ID, mPointer1, mPointer2 and initialize them to -1. Then I checked whether we have one or two fingers down when I received a ACTION_MOVE event. Our onTouch() logic now is as follows:
@Override public onTouch(MotionEvent ev) { if (ev == ACTION_DOWN) { mPointer1 = ev.getPointerId(); // ... save the x & y position of first finger's touch down point } else if (ev == ACTION_UP) { // reset the variables, the user just lifted their finger and doesn't want to do anything mPointer1 = -1; mPointer2 = -1; } else if (ev == ACTION_MOVE) { if (mPointer2 == -1) { // only one finger down, we are dragging } else { // we're either scaling or rotating! } } else if (ev == ACTION_POINTER_DOWN) { mPointer2 = ev.getPointerId(); // ... save x & y of second finger's touch down point } }
We have a new event we are intercepting, ACTION_POINTER_DOWN. This event occurs when a second finger touches down on the view. We now know whether we are dragging or doing something else.
Unfortunately, there is another problem. I want to be able to scale in the X direction (horizontally) and the Y direction (vertically) without caring about the aspect ratio.
It becomes impossible to figure out what the user is trying to do now. I decided the to intercept the touch events on the main CanvasLayout. On the CanvasLayout, if a rotation action is detected, a rotation is applied to the selected view. This brought us to the final onTouch() logic on the AFTextView and CanvasLayout:
AFTextView.java
@Override public onTouch(MotionEvent ev) { if (ev == ACTION_DOWN) { mPointer1 = ev.getPointerId(); ... } else if (ev == ACTION_UP) { mPointer1 = -1; mPointer2 = -1; ... } else if (ev == ACTION_MOVE) { if (mPointer2 == -1) { // only one finger down, we are dragging! } else { // two fingers down, we're scaling! } } else if (ev == ACTION_POINTER_DOWN) { mPointer2 = ev.getPointerId(); ... } }
CanvasLayout.java
@Override public onTouch(MotionEvent ev) { if (ev == ACTION_DOWN) { mPointer1 = ev.getPointerId(); ... } else if (ev == ACTION_POINTER_DOWN) { mPointer2 = ev.getPointerId(); ... } else if (ev == ACTION_MOVE) { // user is moving their first finger in the rotation gesture! // calculate the angle between the second finger and this finger before & after this move } else if (ev == ACTION_UP) { // rotation is finished } return true; }
Great, now we have all the logic in place to know when we need to scale, drag, and rotate our views. The details of how to manipulate the view accordingly warrants another post all together. Rotation in particular had me brushing up on my linear algebra to calculate the angle of change using 4 coordinates (2 coordinates for the position of the fingers before the rotation, 2 coordinates for the position of the fingers after rotation):
Another interesting (read: annoying) thing to deal with was the fact that what would be considered rotating +X degrees in the regular cartesian plane (counter-clockwise) is considered rotating -X degrees in Android views rotation. Sigh...
Anyway, after ironing out some bugs and use some touchSlops to make touches more realistic, the interaction with elements was looking great.
At the end of April Fools day, there had been tens of thousands of campaign posters created on Mobile. I think it's safe to say users had a good time adding, dragging, scaling and rotating views for their favorite lizards.
Someone asked me today how to add ink ripple¹ touch feedback to an image without having to add additional views to your hierarchy which would hurt… - Nick Butcher - Google+
Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
✓ Live Streaming✓ Interactive Chat✓ Private Shows✓ HD Quality
Anya is LIVE right now
FREE
Free to watch • No registration required • HD streaming
I am trying to make use of the elevation property in the latest Android Lollipop preview release. I set the targetSdk to 21 and the theme to Material. Next i added a background shape to a TextView ...
If you’re trying to use elevation, and it wont just work, make sure the background color of the view does not have an alpha channel.
We’ve open-sourced a couple of Android utilities that we use in the Tumblr app for Android. Check it out:
Bookends
A UI widget that allows for headers and footers on lists backed by RecyclerView.
As we were upgrading our app to migrate from ListView to RecyclerView, we found it kind of silly that RecyclerView doesn’t support headers by default. So we built a little wrapper that’ll do this for you.
Remember
An in-memory data store backed by shared preferences.
SharedPreferences are useful but since they’re backed by disk, they can have unpredictable performance characteristics – you’re not guaranteed to always be in memory, and in the case of write operations, you have to hit disk (possibly asynchronously) and remember what you wrote.
Remember takes care of that by putting a write-through cache in front of SharedPreferences. It also gives you a bunch of desirable consistency and concurrency characteristics – access can happen from any number of threads concurrently, and doing a write followed by a read will always return the value you just put. (Even if the value hasn’t been written to disk yet).
Both of these projects are open-sourced under the Apache license, and are available at our Github page. Let us know what you think!
Great article from Jake Wharton explaining not only how to use the Palette library with Picasso, but also how to be clever and resourceful when using third-party libraries.
Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
✓ Live Streaming✓ Interactive Chat✓ Private Shows✓ HD Quality
Anya is LIVE right now
FREE
Free to watch • No registration required • HD streaming
Last weekend, thousands of Instagrammers from all over the world got together for Worldwide InstaMeet 11, one of Instagram’s community-organized, real-world meetups. #WWIM11 was our largest and most geographically diverse InstaMeet ever - thousands of Instagrammers from Muscat to Bushwick...
We could graft the various aspects of Material (keyline grid, in-screen animations, cross-screen transitions) on top of the code base that was, frankly, simply not built to be that flexible. Or we could rebuild the foundation (ahem, yet again) with an eye towards that flexibility and then bring those elements in.
A great piece by Kirill Grouchnikov on how to approach your refactorings.
Two years ago, I published an articled titled Android Performance Case Study to help Android developers understand what tools and technique can be used to identify, track down, and fix performance ...
Great new article by Romain Guy giving some insight in how to debug complex and nuanced performance issues.
Spoilers after the break!
ViewPagerIndicator 3rd party library usage of set Alpha was taking a real toll on performance!
Anya is live and ready to show you everything. Watch her strip, dance, and perform exclusive shows just for you. Interact in real-time and make your fantasies come true.
✓ Live Streaming✓ Interactive Chat✓ Private Shows✓ HD Quality
Anya is LIVE right now
FREE
Free to watch • No registration required • HD streaming
We take screenshots a lot at Tumblr, and it's a bit tedious to find the 'screenshot' button in Android Studio, save the screenshot, navigate to it, and open it in finder. Here's an alias that does it all in one step:
alias ss="adb shell screencap -p | perl -pe 's/\x0D\x0A/\x0A/g' > screen.png && open screen.png"
I like Crashlytics. I like the service they provide: their crash logs have saved my ass countless times. I also like that it's free. However, there is one problem I've run into time and time again: getting new apps setup...